merge
commit
807007649a
9
.hgtags
9
.hgtags
|
|
@ -1,3 +1,4 @@
|
|||
bb38ff1a763738609e1b3cada6d15fa61e5e84b9 2.1.1-release
|
||||
003dd9461bfa479049afcc34545ab3431b147c7c v2start
|
||||
08398e650c222336bb2b6de0cd3bba944aef11b4 2-1rn1
|
||||
0962101bfa7df0643a6e625786025fe7f8a6dc97 2-1-beta-2
|
||||
|
|
@ -26,3 +27,11 @@ c6e6324f5be1401f077ad18a4a0f6b46451c2f7b last_sprint
|
|||
7076e22f9f43f479a4ea75eac447a36364bead5a beta_2.1.3
|
||||
7076e22f9f43f479a4ea75eac447a36364bead5a 2.2.0-beta1
|
||||
9822eb3e25f7fe0c28ffd8aba45c507caa383cbc 2.2.0-beta2
|
||||
b0cd7e150009809a0b5b0a9d5785cd4bb230413a 2.2.0-beta3
|
||||
00a831292231faad7e44c69f76cb96f175b8dfad 2.2.0-beta4
|
||||
98e0d6df638429fd2f0476667504bd5a6b298def 2.3.0-beta1
|
||||
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
|
||||
|
|
|
|||
21
BuildParams
21
BuildParams
|
|
@ -52,6 +52,7 @@ viewer-release.login_channel = "Second Life Release"
|
|||
viewer-release.build_debug_release_separately = true
|
||||
viewer-release.build_viewer_update_version_manager = true
|
||||
|
||||
|
||||
# ========================================
|
||||
# aimee
|
||||
# ========================================
|
||||
|
|
@ -102,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
|
||||
# ========================================
|
||||
|
|
|
|||
3
build.sh
3
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 \
|
||||
|
|
@ -227,7 +228,7 @@ do
|
|||
fi
|
||||
else
|
||||
begin_section "Build$variant"
|
||||
build "$variant" "$build_dir" > "$build_log" 2>&1
|
||||
build "$variant" "$build_dir" >> "$build_log" 2>&1
|
||||
begin_section Tests
|
||||
grep --line-buffered "^##teamcity" "$build_log"
|
||||
end_section Tests
|
||||
|
|
|
|||
|
|
@ -62,19 +62,25 @@ Alejandro Rosenthal
|
|||
VWR-1184
|
||||
Aleric Inglewood
|
||||
SNOW-522
|
||||
SNOW-626
|
||||
SNOW-756
|
||||
SNOW-764
|
||||
VWR-10001
|
||||
VWR-10759
|
||||
VWR-10837
|
||||
VWR-12691
|
||||
VWR-12984
|
||||
VWR-13996
|
||||
VWR-14426
|
||||
SNOW-84
|
||||
SNOW-477
|
||||
SNOW-766
|
||||
STORM-163
|
||||
Ales Beaumont
|
||||
VWR-9352
|
||||
SNOW-240
|
||||
Alexandrea Fride
|
||||
STORM-255
|
||||
Alissa Sabre
|
||||
VWR-81
|
||||
VWR-83
|
||||
|
|
@ -123,6 +129,7 @@ Alissa Sabre
|
|||
VWR-12617
|
||||
VWR-12620
|
||||
VWR-12789
|
||||
SNOW-322
|
||||
Angus Boyd
|
||||
VWR-592
|
||||
Ann Congrejo
|
||||
|
|
@ -139,6 +146,7 @@ Asuka Neely
|
|||
Balp Allen
|
||||
VWR-4157
|
||||
Be Holder
|
||||
SNOW-322
|
||||
SNOW-397
|
||||
Benja Kepler
|
||||
VWR-746
|
||||
|
|
@ -169,9 +177,11 @@ Boroondas Gupte
|
|||
SNOW-610
|
||||
SNOW-624
|
||||
SNOW-737
|
||||
STORM-318
|
||||
VWR-233
|
||||
VWR-20583
|
||||
VWR-20891
|
||||
VWR-23455
|
||||
WEB-262
|
||||
Bulli Schumann
|
||||
CT-218
|
||||
|
|
@ -201,6 +211,8 @@ Catherine Pfeffer
|
|||
Celierra Darling
|
||||
VWR-1274
|
||||
VWR-6975
|
||||
Cypren Christenson
|
||||
STORM-417
|
||||
Dale Glass
|
||||
VWR-120
|
||||
VWR-560
|
||||
|
|
@ -380,6 +392,8 @@ Malwina Dollinger
|
|||
CT-138
|
||||
march Korda
|
||||
SVC-1020
|
||||
Marine Kelley
|
||||
STORM-281
|
||||
Matthew Dowd
|
||||
VWR-1344
|
||||
VWR-1651
|
||||
|
|
@ -401,6 +415,7 @@ McCabe Maxsted
|
|||
VWR-8689
|
||||
VWR-9007
|
||||
Michelle2 Zenovka
|
||||
STORM-477
|
||||
VWR-2652
|
||||
VWR-2662
|
||||
VWR-2834
|
||||
|
|
@ -528,6 +543,7 @@ Pf Shan
|
|||
CT-230
|
||||
CT-231
|
||||
CT-321
|
||||
SNOW-422
|
||||
princess niven
|
||||
VWR-5733
|
||||
CT-85
|
||||
|
|
@ -549,16 +565,19 @@ 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
|
||||
STORM-422
|
||||
VWR-2488
|
||||
VWR-9557
|
||||
VWR-11128
|
||||
|
|
@ -582,6 +601,8 @@ Salahzar Stenvaag
|
|||
CT-321
|
||||
Sammy Frederix
|
||||
VWR-6186
|
||||
Satomi Ahn
|
||||
STORM-501
|
||||
Scrippy Scofield
|
||||
VWR-3748
|
||||
Seg Baphomet
|
||||
|
|
@ -640,6 +661,7 @@ Strife Onizuka
|
|||
VWR-183
|
||||
VWR-2265
|
||||
VWR-4111
|
||||
SNOW-691
|
||||
Tayra Dagostino
|
||||
SNOW-517
|
||||
SNOW-543
|
||||
|
|
@ -660,6 +682,8 @@ Techwolf Lupindo
|
|||
SNOW-592
|
||||
SNOW-649
|
||||
SNOW-650
|
||||
SNOW-651
|
||||
SNOW-654
|
||||
SNOW-687
|
||||
SNOW-680
|
||||
SNOW-681
|
||||
|
|
@ -667,6 +691,7 @@ Techwolf Lupindo
|
|||
SNOW-690
|
||||
SNOW-746
|
||||
VWR-12385
|
||||
VWR-20893
|
||||
tenebrous pau
|
||||
VWR-247
|
||||
Tharax Ferraris
|
||||
|
|
@ -689,6 +714,8 @@ Thraxis Epsilon
|
|||
VWR-383
|
||||
tiamat bingyi
|
||||
CT-246
|
||||
Tofu Buzzard
|
||||
STORM-546
|
||||
TraductoresAnonimos Alter
|
||||
CT-324
|
||||
Tue Torok
|
||||
|
|
@ -734,8 +761,19 @@ Whoops Babii
|
|||
VWR-8298
|
||||
Wilton Lundquist
|
||||
VWR-7682
|
||||
WolfPup Lowenhar
|
||||
SNOW-622
|
||||
SNOW-772
|
||||
STORM-102
|
||||
STORM-103
|
||||
STORM-143
|
||||
VWR-20741
|
||||
VWR-20933
|
||||
Zai Lynch
|
||||
VWR-19505
|
||||
Wolfpup Lowenhar
|
||||
STORM-255
|
||||
STORM-256
|
||||
Zarkonnen Decosta
|
||||
VWR-253
|
||||
Zi Ree
|
||||
|
|
|
|||
|
|
@ -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,26 @@
|
|||
# -*- 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)
|
||||
if (INSTALL_PROPRIETARY)
|
||||
include(Prebuilt)
|
||||
use_prebuilt_binary(fmod)
|
||||
endif (INSTALL_PROPRIETARY)
|
||||
|
||||
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
|
||||
)
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -87,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
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ void export_test_floaters()
|
|||
std::string delim = gDirUtilp->getDirDelimiter();
|
||||
std::string xui_dir = get_xui_dir() + "en" + delim;
|
||||
std::string filename;
|
||||
while (gDirUtilp->getNextFileInDir(xui_dir, "floater_test_*.xml", filename, false))
|
||||
while (gDirUtilp->getNextFileInDir(xui_dir, "floater_test_*.xml", filename))
|
||||
{
|
||||
if (filename.find("_new.xml") != std::string::npos)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -216,7 +216,7 @@ gboolean rotate_image_cb(gpointer data)
|
|||
std::string next_image_filename(std::string& image_path)
|
||||
{
|
||||
std::string image_filename;
|
||||
gDirUtilp->getNextFileInDir(image_path, "/*.jpg", image_filename, true);
|
||||
gDirUtilp->getNextFileInDir(image_path, "/*.jpg", image_filename);
|
||||
return image_path + "/" + image_filename;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ include(LLVFS)
|
|||
|
||||
include_directories(
|
||||
${LLAUDIO_INCLUDE_DIRS}
|
||||
${FMOD_INCLUDE_DIR}
|
||||
${LLCOMMON_INCLUDE_DIRS}
|
||||
${LLMATH_INCLUDE_DIRS}
|
||||
${LLMESSAGE_INCLUDE_DIRS}
|
||||
|
|
@ -45,6 +44,10 @@ set(llaudio_HEADER_FILES
|
|||
)
|
||||
|
||||
if (FMOD)
|
||||
include_directories(
|
||||
${FMOD_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
list(APPEND llaudio_SOURCE_FILES
|
||||
llaudioengine_fmod.cpp
|
||||
lllistener_fmod.cpp
|
||||
|
|
|
|||
|
|
@ -120,6 +120,13 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro
|
|||
+ ((U32) wav_header[5] << 8)
|
||||
+ wav_header[4];
|
||||
|
||||
if (chunk_length > physical_file_size - file_pos - 4)
|
||||
{
|
||||
infile.close();
|
||||
error_msg = "SoundFileInvalidChunkSize";
|
||||
return(LLVORBISENC_CHUNK_SIZE_ERR);
|
||||
}
|
||||
|
||||
// llinfos << "chunk found: '" << wav_header[0] << wav_header[1] << wav_header[2] << wav_header[3] << "'" << llendl;
|
||||
|
||||
if (!(strncmp((char *)&(wav_header[0]),"fmt ",4)))
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ const S32 LLVORBISENC_MULTICHANNEL_ERR = 7; // can't do stereo
|
|||
const S32 LLVORBISENC_UNSUPPORTED_SAMPLE_RATE = 8; // unsupported sample rate
|
||||
const S32 LLVORBISENC_UNSUPPORTED_WORD_SIZE = 9; // unsupported word size
|
||||
const S32 LLVORBISENC_CLIP_TOO_LONG = 10; // source file is too long
|
||||
const S32 LLVORBISENC_CHUNK_SIZE_ERR = 11; // chunk size is wrong
|
||||
|
||||
const F32 LLVORBIS_CLIP_MAX_TIME = 10.0f;
|
||||
const U8 LLVORBIS_CLIP_MAX_CHANNELS = 2;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ set(llcommon_SOURCE_FILES
|
|||
llapp.cpp
|
||||
llapr.cpp
|
||||
llassettype.cpp
|
||||
llavatarname.cpp
|
||||
llbase32.cpp
|
||||
llbase64.cpp
|
||||
llcommon.cpp
|
||||
|
|
@ -69,6 +70,7 @@ set(llcommon_SOURCE_FILES
|
|||
llmemorystream.cpp
|
||||
llmemtype.cpp
|
||||
llmetrics.cpp
|
||||
llmetricperformancetester.cpp
|
||||
llmortician.cpp
|
||||
lloptioninterface.cpp
|
||||
llptrto.cpp
|
||||
|
|
@ -115,6 +117,7 @@ set(llcommon_HEADER_FILES
|
|||
llallocator.h
|
||||
llallocator_heap_profile.h
|
||||
llagentconstants.h
|
||||
llavatarname.h
|
||||
llapp.h
|
||||
llapr.h
|
||||
llassettype.h
|
||||
|
|
@ -184,6 +187,7 @@ set(llcommon_HEADER_FILES
|
|||
llmemorystream.h
|
||||
llmemtype.h
|
||||
llmetrics.h
|
||||
llmetricperformancetester.h
|
||||
llmortician.h
|
||||
llnametable.h
|
||||
lloptioninterface.h
|
||||
|
|
@ -252,8 +256,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)
|
||||
|
|
|
|||
|
|
@ -90,6 +90,10 @@ S32 LL_HEARTBEAT_SIGNAL = (SIGRTMAX >= 0) ? (SIGRTMAX-0) : SIGUSR2;
|
|||
// the static application instance
|
||||
LLApp* LLApp::sApplication = NULL;
|
||||
|
||||
// Allows the generation of core files for post mortem under gdb
|
||||
// and disables crashlogger
|
||||
BOOL LLApp::sDisableCrashlogger = FALSE;
|
||||
|
||||
// Local flag for whether or not to do logging in signal handlers.
|
||||
//static
|
||||
BOOL LLApp::sLogInSignal = FALSE;
|
||||
|
|
@ -461,11 +465,30 @@ bool LLApp::isQuitting()
|
|||
return (APP_STATUS_QUITTING == sStatus);
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLApp::isExiting()
|
||||
{
|
||||
return isQuitting() || isError();
|
||||
}
|
||||
|
||||
void LLApp::disableCrashlogger()
|
||||
{
|
||||
// Disable Breakpad exception handler.
|
||||
if (mExceptionHandler != 0)
|
||||
{
|
||||
delete mExceptionHandler;
|
||||
mExceptionHandler = 0;
|
||||
}
|
||||
|
||||
sDisableCrashlogger = TRUE;
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLApp::isCrashloggerDisabled()
|
||||
{
|
||||
return (sDisableCrashlogger == TRUE);
|
||||
}
|
||||
|
||||
#if !LL_WINDOWS
|
||||
// static
|
||||
U32 LLApp::getSigChildCount()
|
||||
|
|
@ -799,6 +822,15 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
|
|||
{
|
||||
llwarns << "Signal handler - Flagging error status and waiting for shutdown" << llendl;
|
||||
}
|
||||
|
||||
if (LLApp::isCrashloggerDisabled()) // Don't gracefully handle any signal, crash and core for a gdb post mortem
|
||||
{
|
||||
clear_signals();
|
||||
llwarns << "Fatal signal received, not handling the crash here, passing back to operating system" << llendl;
|
||||
raise(signum);
|
||||
return;
|
||||
}
|
||||
|
||||
// Flag status to ERROR, so thread_error does its work.
|
||||
LLApp::setError();
|
||||
// Block in the signal handler until somebody says that we're done.
|
||||
|
|
|
|||
|
|
@ -189,6 +189,11 @@ public:
|
|||
//
|
||||
virtual bool mainLoop() = 0; // Override for the application main loop. Needs to at least gracefully notice the QUITTING state and exit.
|
||||
|
||||
//
|
||||
// Crash logging
|
||||
//
|
||||
void disableCrashlogger(); // Let the OS handle the crashes
|
||||
static bool isCrashloggerDisabled(); // Get the here above set value
|
||||
|
||||
//
|
||||
// Application status
|
||||
|
|
@ -280,6 +285,7 @@ protected:
|
|||
static void setStatus(EAppStatus status); // Use this to change the application status.
|
||||
static EAppStatus sStatus; // Reflects current application status
|
||||
static BOOL sErrorThreadRunning; // Set while the error thread is running
|
||||
static BOOL sDisableCrashlogger; // Let the OS handle crashes for us.
|
||||
|
||||
#if !LL_WINDOWS
|
||||
static LLAtomicU32* sSigChildCount; // Number of SIGCHLDs received.
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ public:
|
|||
|
||||
LLDynamicArray(S32 size=0) : std::vector<Type>(size) { if (size < BlockSize) std::vector<Type>::reserve(BlockSize); }
|
||||
|
||||
void reset() { std::vector<Type>::resize(0); }
|
||||
void reset() { std::vector<Type>::clear(); }
|
||||
|
||||
// ACCESSORS
|
||||
const Type& get(S32 index) const { return std::vector<Type>::operator[](index); }
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ bool LLFastTimer::sPauseHistory = 0;
|
|||
bool LLFastTimer::sResetHistory = 0;
|
||||
LLFastTimer::CurTimerData LLFastTimer::sCurTimerData;
|
||||
BOOL LLFastTimer::sLog = FALSE;
|
||||
std::string LLFastTimer::sLogName = "";
|
||||
BOOL LLFastTimer::sMetricLog = FALSE;
|
||||
LLMutex* LLFastTimer::sLogLock = NULL;
|
||||
std::queue<LLSD> LLFastTimer::sLogQueue;
|
||||
|
|
|
|||
|
|
@ -211,6 +211,7 @@ public:
|
|||
static std::queue<LLSD> sLogQueue;
|
||||
static BOOL sLog;
|
||||
static BOOL sMetricLog;
|
||||
static std::string sLogName;
|
||||
static bool sPauseHistory;
|
||||
static bool sResetHistory;
|
||||
static U64 sTimerCycles;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,254 @@
|
|||
/**
|
||||
* @file llmetricperformancetester.cpp
|
||||
* @brief LLMetricPerformanceTesterBasic and LLMetricPerformanceTesterWithSession classes implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&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 "indra_constants.h"
|
||||
#include "llerror.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llstat.h"
|
||||
#include "lltreeiterators.h"
|
||||
#include "llmetricperformancetester.h"
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
// LLMetricPerformanceTesterBasic : static methods and testers management
|
||||
//----------------------------------------------------------------------------------------------
|
||||
|
||||
LLMetricPerformanceTesterBasic::name_tester_map_t LLMetricPerformanceTesterBasic::sTesterMap ;
|
||||
|
||||
/*static*/
|
||||
void LLMetricPerformanceTesterBasic::cleanClass()
|
||||
{
|
||||
for (name_tester_map_t::iterator iter = sTesterMap.begin() ; iter != sTesterMap.end() ; ++iter)
|
||||
{
|
||||
delete iter->second ;
|
||||
}
|
||||
sTesterMap.clear() ;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
BOOL LLMetricPerformanceTesterBasic::addTester(LLMetricPerformanceTesterBasic* tester)
|
||||
{
|
||||
llassert_always(tester != NULL);
|
||||
std::string name = tester->getTesterName() ;
|
||||
if (getTester(name))
|
||||
{
|
||||
llerrs << "Tester name is already used by some other tester : " << name << llendl ;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sTesterMap.insert(std::make_pair(name, tester));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
LLMetricPerformanceTesterBasic* LLMetricPerformanceTesterBasic::getTester(std::string name)
|
||||
{
|
||||
// Check for the requested metric name
|
||||
name_tester_map_t::iterator found_it = sTesterMap.find(name) ;
|
||||
if (found_it != sTesterMap.end())
|
||||
{
|
||||
return found_it->second ;
|
||||
}
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
// Return TRUE if this metric is requested or if the general default "catch all" metric is requested
|
||||
BOOL LLMetricPerformanceTesterBasic::isMetricLogRequested(std::string name)
|
||||
{
|
||||
return (LLFastTimer::sMetricLog && ((LLFastTimer::sLogName == name) || (LLFastTimer::sLogName == DEFAULT_METRIC_NAME)));
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
// LLMetricPerformanceTesterBasic : Tester instance methods
|
||||
//----------------------------------------------------------------------------------------------
|
||||
|
||||
LLMetricPerformanceTesterBasic::LLMetricPerformanceTesterBasic(std::string name) :
|
||||
mName(name),
|
||||
mCount(0)
|
||||
{
|
||||
if (mName == std::string())
|
||||
{
|
||||
llerrs << "LLMetricPerformanceTesterBasic construction invalid : Empty name passed to constructor" << llendl ;
|
||||
}
|
||||
|
||||
mValidInstance = LLMetricPerformanceTesterBasic::addTester(this) ;
|
||||
}
|
||||
|
||||
LLMetricPerformanceTesterBasic::~LLMetricPerformanceTesterBasic()
|
||||
{
|
||||
}
|
||||
|
||||
void LLMetricPerformanceTesterBasic::preOutputTestResults(LLSD* sd)
|
||||
{
|
||||
incrementCurrentCount() ;
|
||||
(*sd)[getCurrentLabelName()]["Name"] = mName ;
|
||||
}
|
||||
|
||||
void LLMetricPerformanceTesterBasic::postOutputTestResults(LLSD* sd)
|
||||
{
|
||||
LLMutexLock lock(LLFastTimer::sLogLock);
|
||||
LLFastTimer::sLogQueue.push((*sd));
|
||||
}
|
||||
|
||||
void LLMetricPerformanceTesterBasic::outputTestResults()
|
||||
{
|
||||
LLSD sd;
|
||||
|
||||
preOutputTestResults(&sd) ;
|
||||
outputTestRecord(&sd) ;
|
||||
postOutputTestResults(&sd) ;
|
||||
}
|
||||
|
||||
void LLMetricPerformanceTesterBasic::addMetric(std::string str)
|
||||
{
|
||||
mMetricStrings.push_back(str) ;
|
||||
}
|
||||
|
||||
/*virtual*/
|
||||
void LLMetricPerformanceTesterBasic::analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current)
|
||||
{
|
||||
resetCurrentCount() ;
|
||||
|
||||
std::string current_label = getCurrentLabelName();
|
||||
BOOL in_base = (*base).has(current_label) ;
|
||||
BOOL in_current = (*current).has(current_label) ;
|
||||
|
||||
while(in_base || in_current)
|
||||
{
|
||||
LLSD::String label = current_label ;
|
||||
|
||||
if(in_base && in_current)
|
||||
{
|
||||
*os << llformat("%s\n", label.c_str()) ;
|
||||
|
||||
for(U32 index = 0 ; index < mMetricStrings.size() ; index++)
|
||||
{
|
||||
switch((*current)[label][ mMetricStrings[index] ].type())
|
||||
{
|
||||
case LLSD::TypeInteger:
|
||||
compareTestResults(os, mMetricStrings[index],
|
||||
(S32)((*base)[label][ mMetricStrings[index] ].asInteger()), (S32)((*current)[label][ mMetricStrings[index] ].asInteger())) ;
|
||||
break ;
|
||||
case LLSD::TypeReal:
|
||||
compareTestResults(os, mMetricStrings[index],
|
||||
(F32)((*base)[label][ mMetricStrings[index] ].asReal()), (F32)((*current)[label][ mMetricStrings[index] ].asReal())) ;
|
||||
break;
|
||||
default:
|
||||
llerrs << "unsupported metric " << mMetricStrings[index] << " LLSD type: " << (S32)(*current)[label][ mMetricStrings[index] ].type() << llendl ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
incrementCurrentCount();
|
||||
current_label = getCurrentLabelName();
|
||||
in_base = (*base).has(current_label) ;
|
||||
in_current = (*current).has(current_label) ;
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/
|
||||
void LLMetricPerformanceTesterBasic::compareTestResults(std::ofstream* os, std::string metric_string, S32 v_base, S32 v_current)
|
||||
{
|
||||
*os << llformat(" ,%s, %d, %d, %d, %.4f\n", metric_string.c_str(), v_base, v_current,
|
||||
v_current - v_base, (v_base != 0) ? 100.f * v_current / v_base : 0) ;
|
||||
}
|
||||
|
||||
/*virtual*/
|
||||
void LLMetricPerformanceTesterBasic::compareTestResults(std::ofstream* os, std::string metric_string, F32 v_base, F32 v_current)
|
||||
{
|
||||
*os << llformat(" ,%s, %.4f, %.4f, %.4f, %.4f\n", metric_string.c_str(), v_base, v_current,
|
||||
v_current - v_base, (fabs(v_base) > 0.0001f) ? 100.f * v_current / v_base : 0.f ) ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
// LLMetricPerformanceTesterWithSession
|
||||
//----------------------------------------------------------------------------------------------
|
||||
|
||||
LLMetricPerformanceTesterWithSession::LLMetricPerformanceTesterWithSession(std::string name) :
|
||||
LLMetricPerformanceTesterBasic(name),
|
||||
mBaseSessionp(NULL),
|
||||
mCurrentSessionp(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
LLMetricPerformanceTesterWithSession::~LLMetricPerformanceTesterWithSession()
|
||||
{
|
||||
if (mBaseSessionp)
|
||||
{
|
||||
delete mBaseSessionp ;
|
||||
mBaseSessionp = NULL ;
|
||||
}
|
||||
if (mCurrentSessionp)
|
||||
{
|
||||
delete mCurrentSessionp ;
|
||||
mCurrentSessionp = NULL ;
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/
|
||||
void LLMetricPerformanceTesterWithSession::analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current)
|
||||
{
|
||||
// Load the base session
|
||||
resetCurrentCount() ;
|
||||
mBaseSessionp = loadTestSession(base) ;
|
||||
|
||||
// Load the current session
|
||||
resetCurrentCount() ;
|
||||
mCurrentSessionp = loadTestSession(current) ;
|
||||
|
||||
if (!mBaseSessionp || !mCurrentSessionp)
|
||||
{
|
||||
llerrs << "Error loading test sessions." << llendl ;
|
||||
}
|
||||
|
||||
// Compare
|
||||
compareTestSessions(os) ;
|
||||
|
||||
// Release memory
|
||||
if (mBaseSessionp)
|
||||
{
|
||||
delete mBaseSessionp ;
|
||||
mBaseSessionp = NULL ;
|
||||
}
|
||||
if (mCurrentSessionp)
|
||||
{
|
||||
delete mCurrentSessionp ;
|
||||
mCurrentSessionp = NULL ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
// LLTestSession
|
||||
//----------------------------------------------------------------------------------------------
|
||||
|
||||
LLMetricPerformanceTesterWithSession::LLTestSession::~LLTestSession()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
/**
|
||||
* @file llmetricperformancetester.h
|
||||
* @brief LLMetricPerformanceTesterBasic and LLMetricPerformanceTesterWithSession classes definition
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&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_METRICPERFORMANCETESTER_H
|
||||
#define LL_METRICPERFORMANCETESTER_H
|
||||
|
||||
const std::string DEFAULT_METRIC_NAME("metric");
|
||||
|
||||
/**
|
||||
* @class LLMetricPerformanceTesterBasic
|
||||
* @brief Performance Metric Base Class
|
||||
*/
|
||||
class LL_COMMON_API LLMetricPerformanceTesterBasic
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Creates a basic tester instance.
|
||||
* @param[in] name - Unique string identifying this tester instance.
|
||||
*/
|
||||
LLMetricPerformanceTesterBasic(std::string name);
|
||||
virtual ~LLMetricPerformanceTesterBasic();
|
||||
|
||||
/**
|
||||
* @return Returns true if the instance has been added to the tester map.
|
||||
* Need to be tested after creation of a tester instance so to know if the tester is correctly handled.
|
||||
* A tester might not be added to the map if another tester with the same name already exists.
|
||||
*/
|
||||
BOOL isValid() const { return mValidInstance; }
|
||||
|
||||
/**
|
||||
* @brief Write a set of test results to the log LLSD.
|
||||
*/
|
||||
void outputTestResults() ;
|
||||
|
||||
/**
|
||||
* @brief Compare the test results.
|
||||
* By default, compares the test results against the baseline one by one, item by item,
|
||||
* in the increasing order of the LLSD record counter, starting from the first one.
|
||||
*/
|
||||
virtual void analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current) ;
|
||||
|
||||
/**
|
||||
* @return Returns the number of the test metrics in this tester instance.
|
||||
*/
|
||||
S32 getNumberOfMetrics() const { return mMetricStrings.size() ;}
|
||||
/**
|
||||
* @return Returns the metric name at index
|
||||
* @param[in] index - Index on the list of metrics managed by this tester instance.
|
||||
*/
|
||||
std::string getMetricName(S32 index) const { return mMetricStrings[index] ;}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @return Returns the name of this tester instance.
|
||||
*/
|
||||
std::string getTesterName() const { return mName ;}
|
||||
|
||||
/**
|
||||
* @brief Insert a new metric to be managed by this tester instance.
|
||||
* @param[in] str - Unique string identifying the new metric.
|
||||
*/
|
||||
void addMetric(std::string str) ;
|
||||
|
||||
/**
|
||||
* @brief Compare test results, provided in 2 flavors: compare integers and compare floats.
|
||||
* @param[out] os - Formatted output string holding the compared values.
|
||||
* @param[in] metric_string - Name of the metric.
|
||||
* @param[in] v_base - Base value of the metric.
|
||||
* @param[in] v_current - Current value of the metric.
|
||||
*/
|
||||
virtual void compareTestResults(std::ofstream* os, std::string metric_string, S32 v_base, S32 v_current) ;
|
||||
virtual void compareTestResults(std::ofstream* os, std::string metric_string, F32 v_base, F32 v_current) ;
|
||||
|
||||
/**
|
||||
* @brief Reset internal record count. Count starts with 1.
|
||||
*/
|
||||
void resetCurrentCount() { mCount = 1; }
|
||||
/**
|
||||
* @brief Increment internal record count.
|
||||
*/
|
||||
void incrementCurrentCount() { mCount++; }
|
||||
/**
|
||||
* @return Returns the label to be used for the current count. It's "TesterName"-"Count".
|
||||
*/
|
||||
std::string getCurrentLabelName() const { return llformat("%s-%d", mName.c_str(), mCount) ;}
|
||||
|
||||
/**
|
||||
* @brief Write a test record to the LLSD. Implementers need to overload this method.
|
||||
* @param[out] sd - The LLSD record to store metric data into.
|
||||
*/
|
||||
virtual void outputTestRecord(LLSD* sd) = 0 ;
|
||||
|
||||
private:
|
||||
void preOutputTestResults(LLSD* sd) ;
|
||||
void postOutputTestResults(LLSD* sd) ;
|
||||
|
||||
std::string mName ; // Name of this tester instance
|
||||
S32 mCount ; // Current record count
|
||||
BOOL mValidInstance; // TRUE if the instance is managed by the map
|
||||
std::vector< std::string > mMetricStrings ; // Metrics strings
|
||||
|
||||
// Static members managing the collection of testers
|
||||
public:
|
||||
// Map of all the tester instances in use
|
||||
typedef std::map< std::string, LLMetricPerformanceTesterBasic* > name_tester_map_t;
|
||||
static name_tester_map_t sTesterMap ;
|
||||
|
||||
/**
|
||||
* @return Returns a pointer to the tester
|
||||
* @param[in] name - Name of the tester instance queried.
|
||||
*/
|
||||
static LLMetricPerformanceTesterBasic* getTester(std::string name) ;
|
||||
|
||||
/**
|
||||
* @return Returns TRUE if that metric *or* the default catch all metric has been requested to be logged
|
||||
* @param[in] name - Name of the tester queried.
|
||||
*/
|
||||
static BOOL isMetricLogRequested(std::string name);
|
||||
|
||||
/**
|
||||
* @return Returns TRUE if there's a tester defined, FALSE otherwise.
|
||||
*/
|
||||
static BOOL hasMetricPerformanceTesters() { return !sTesterMap.empty() ;}
|
||||
/**
|
||||
* @brief Delete all testers and reset the tester map
|
||||
*/
|
||||
static void cleanClass() ;
|
||||
|
||||
private:
|
||||
// Add a tester to the map. Returns false if adding fails.
|
||||
static BOOL addTester(LLMetricPerformanceTesterBasic* tester) ;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class LLMetricPerformanceTesterWithSession
|
||||
* @brief Performance Metric Class with custom session
|
||||
*/
|
||||
class LL_COMMON_API LLMetricPerformanceTesterWithSession : public LLMetricPerformanceTesterBasic
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @param[in] name - Unique string identifying this tester instance.
|
||||
*/
|
||||
LLMetricPerformanceTesterWithSession(std::string name);
|
||||
virtual ~LLMetricPerformanceTesterWithSession();
|
||||
|
||||
/**
|
||||
* @brief Compare the test results.
|
||||
* This will be loading the base and current sessions and compare them using the virtual
|
||||
* abstract methods loadTestSession() and compareTestSessions()
|
||||
*/
|
||||
virtual void analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current) ;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @class LLMetricPerformanceTesterWithSession::LLTestSession
|
||||
* @brief Defines an interface for the two abstract virtual functions loadTestSession() and compareTestSessions()
|
||||
*/
|
||||
class LL_COMMON_API LLTestSession
|
||||
{
|
||||
public:
|
||||
virtual ~LLTestSession() ;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Convert an LLSD log into a test session.
|
||||
* @param[in] log - The LLSD record
|
||||
* @return Returns the record as a test session
|
||||
*/
|
||||
virtual LLMetricPerformanceTesterWithSession::LLTestSession* loadTestSession(LLSD* log) = 0;
|
||||
|
||||
/**
|
||||
* @brief Compare the base session and the target session. Assumes base and current sessions have been loaded.
|
||||
* @param[out] os - The comparison result as a standard stream
|
||||
*/
|
||||
virtual void compareTestSessions(std::ofstream* os) = 0;
|
||||
|
||||
LLTestSession* mBaseSessionp;
|
||||
LLTestSession* mCurrentSessionp;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -58,6 +58,11 @@ void LLProcessLauncher::setWorkingDirectory(const std::string &dir)
|
|||
mWorkingDir = dir;
|
||||
}
|
||||
|
||||
const std::string& LLProcessLauncher::getExecutable() const
|
||||
{
|
||||
return mExecutable;
|
||||
}
|
||||
|
||||
void LLProcessLauncher::clearArguments()
|
||||
{
|
||||
mLaunchArguments.clear();
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ public:
|
|||
void setExecutable(const std::string &executable);
|
||||
void setWorkingDirectory(const std::string &dir);
|
||||
|
||||
const std::string& getExecutable() const;
|
||||
|
||||
void clearArguments();
|
||||
void addArgument(const std::string &arg);
|
||||
void addArgument(const char *arg);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -635,6 +635,26 @@ U32 LLMemoryInfo::getPhysicalMemoryClamped() const
|
|||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLMemoryInfo::getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_virtual_mem_kb)
|
||||
{
|
||||
#if LL_WINDOWS
|
||||
MEMORYSTATUSEX state;
|
||||
state.dwLength = sizeof(state);
|
||||
GlobalMemoryStatusEx(&state);
|
||||
|
||||
avail_physical_mem_kb = (U32)(state.ullAvailPhys/1024) ;
|
||||
avail_virtual_mem_kb = (U32)(state.ullAvailVirtual/1024) ;
|
||||
|
||||
#else
|
||||
//do not know how to collect available memory info for other systems.
|
||||
//leave it blank here for now.
|
||||
|
||||
avail_physical_mem_kb = -1 ;
|
||||
avail_virtual_mem_kb = -1 ;
|
||||
#endif
|
||||
}
|
||||
|
||||
void LLMemoryInfo::stream(std::ostream& s) const
|
||||
{
|
||||
#if LL_WINDOWS
|
||||
|
|
|
|||
|
|
@ -114,6 +114,9 @@ public:
|
|||
** be returned.
|
||||
*/
|
||||
U32 getPhysicalMemoryClamped() const; ///< Memory size in clamped bytes
|
||||
|
||||
//get the available memory infomation in KiloBytes.
|
||||
static void getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_virtual_mem_kb);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
const S32 LL_VERSION_MAJOR = 2;
|
||||
const S32 LL_VERSION_MINOR = 1;
|
||||
const S32 LL_VERSION_PATCH = 0;
|
||||
const S32 LL_VERSION_BUILD = 13828;
|
||||
const S32 LL_VERSION_BUILD = 211776;
|
||||
|
||||
const char * const LL_CHANNEL = "Second Life Server";
|
||||
|
||||
|
|
|
|||
|
|
@ -28,10 +28,14 @@
|
|||
#define LL_LLVERSIONVIEWER_H
|
||||
|
||||
const S32 LL_VERSION_MAJOR = 2;
|
||||
const S32 LL_VERSION_MINOR = 2;
|
||||
const S32 LL_VERSION_PATCH = 1;
|
||||
const S32 LL_VERSION_BUILD = 0;
|
||||
const S32 LL_VERSION_MINOR = 4;
|
||||
const S32 LL_VERSION_PATCH = 0;
|
||||
const S32 LL_VERSION_BUILD = 211776;
|
||||
|
||||
const char * const LL_CHANNEL = "Second Life Developer";
|
||||
|
||||
#if LL_DARWIN
|
||||
const char * const LL_VERSION_BUNDLE_ID = "com.secondlife.snowglobe.viewer";
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@
|
|||
|
||||
#include "llimagedimensionsinfo.h"
|
||||
|
||||
// Value is true if one of Libjpeg's functions has encountered an error while working.
|
||||
static bool sJpegErrorEncountered = false;
|
||||
|
||||
bool LLImageDimensionsInfo::load(const std::string& src_filename,U32 codec)
|
||||
{
|
||||
clean();
|
||||
|
|
@ -101,9 +104,17 @@ bool LLImageDimensionsInfo::getImageDimensionsPng()
|
|||
return true;
|
||||
}
|
||||
|
||||
// Called instead of exit() if Libjpeg encounters an error.
|
||||
void on_jpeg_error(j_common_ptr cinfo)
|
||||
{
|
||||
(void) cinfo;
|
||||
sJpegErrorEncountered = true;
|
||||
llwarns << "Libjpeg has encountered an error!" << llendl;
|
||||
}
|
||||
|
||||
bool LLImageDimensionsInfo::getImageDimensionsJpeg()
|
||||
{
|
||||
sJpegErrorEncountered = false;
|
||||
clean();
|
||||
FILE *fp = fopen (mSrcFilename.c_str(), "rb");
|
||||
if (fp == NULL)
|
||||
|
|
@ -115,6 +126,9 @@ bool LLImageDimensionsInfo::getImageDimensionsJpeg()
|
|||
jpeg_error_mgr jerr;
|
||||
jpeg_decompress_struct cinfo;
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
// Call our function instead of exit() if Libjpeg encounters an error.
|
||||
// This is done to avoid crash in this case (STORM-472).
|
||||
cinfo.err->error_exit = on_jpeg_error;
|
||||
|
||||
jpeg_create_decompress (&cinfo);
|
||||
jpeg_stdio_src (&cinfo, fp);
|
||||
|
|
@ -128,6 +142,6 @@ bool LLImageDimensionsInfo::getImageDimensionsJpeg()
|
|||
jpeg_destroy_decompress(&cinfo);
|
||||
fclose(fp);
|
||||
|
||||
return true;
|
||||
return !sJpegErrorEncountered;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@
|
|||
#include "lldir.h"
|
||||
#include "llimagej2c.h"
|
||||
#include "llmemtype.h"
|
||||
#include "lltimer.h"
|
||||
#include "llmath.h"
|
||||
|
||||
typedef LLImageJ2CImpl* (*CreateLLImageJ2CFunction)();
|
||||
typedef void (*DestroyLLImageJ2CFunction)(LLImageJ2CImpl*);
|
||||
|
|
@ -51,6 +53,10 @@ LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl();
|
|||
void fallbackDestroyLLImageJ2CImpl(LLImageJ2CImpl* impl);
|
||||
const char* fallbackEngineInfoLLImageJ2CImpl();
|
||||
|
||||
// Test data gathering handle
|
||||
LLImageCompressionTester* LLImageJ2C::sTesterp = NULL ;
|
||||
const std::string sTesterName("ImageCompressionTester");
|
||||
|
||||
//static
|
||||
//Loads the required "create", "destroy" and "engineinfo" functions needed
|
||||
void LLImageJ2C::openDSO()
|
||||
|
|
@ -71,8 +77,8 @@ void LLImageJ2C::openDSO()
|
|||
#endif
|
||||
|
||||
dso_path = gDirUtilp->findFile(dso_name,
|
||||
gDirUtilp->getAppRODataDir(),
|
||||
gDirUtilp->getExecutableDir());
|
||||
gDirUtilp->getAppRODataDir(),
|
||||
gDirUtilp->getExecutableDir());
|
||||
|
||||
j2cimpl_dso_handle = NULL;
|
||||
j2cimpl_dso_memory_pool = NULL;
|
||||
|
|
@ -102,7 +108,7 @@ void LLImageJ2C::openDSO()
|
|||
//so lets check for a destruction function
|
||||
rv = apr_dso_sym((apr_dso_handle_sym_t*)&dest_func,
|
||||
j2cimpl_dso_handle,
|
||||
"destroyLLImageJ2CKDU");
|
||||
"destroyLLImageJ2CKDU");
|
||||
if ( rv == APR_SUCCESS )
|
||||
{
|
||||
//we've loaded the destroy function ok
|
||||
|
|
@ -195,6 +201,17 @@ LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C),
|
|||
{ // Array size is MAX_DISCARD_LEVEL+1
|
||||
mDataSizes[i] = 0;
|
||||
}
|
||||
|
||||
// If that test log has ben requested but not yet created, create it
|
||||
if (LLMetricPerformanceTesterBasic::isMetricLogRequested(sTesterName) && !LLMetricPerformanceTesterBasic::getTester(sTesterName))
|
||||
{
|
||||
sTesterp = new LLImageCompressionTester() ;
|
||||
if (!sTesterp->isValid())
|
||||
{
|
||||
delete sTesterp;
|
||||
sTesterp = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
|
|
@ -280,6 +297,7 @@ BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time)
|
|||
// Returns TRUE to mean done, whether successful or not.
|
||||
BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count )
|
||||
{
|
||||
LLTimer elapsed;
|
||||
LLMemType mt1(mMemType);
|
||||
|
||||
BOOL res = TRUE;
|
||||
|
|
@ -318,6 +336,21 @@ BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir
|
|||
LLImage::setLastError(mLastError);
|
||||
}
|
||||
|
||||
LLImageCompressionTester* tester = (LLImageCompressionTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
|
||||
if (tester)
|
||||
{
|
||||
// Decompression stat gathering
|
||||
// Note that we *do not* take into account the decompression failures data so we might overestimate the time spent processing
|
||||
|
||||
// Always add the decompression time to the stat
|
||||
tester->updateDecompressionStats(elapsed.getElapsedTimeF32()) ;
|
||||
if (res)
|
||||
{
|
||||
// The whole data stream is finally decompressed when res is returned as TRUE
|
||||
tester->updateDecompressionStats(this->getDataSize(), raw_imagep->getDataSize()) ;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -330,6 +363,7 @@ BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, F32 encode_time)
|
|||
|
||||
BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time)
|
||||
{
|
||||
LLTimer elapsed;
|
||||
LLMemType mt1(mMemType);
|
||||
resetLastError();
|
||||
BOOL res = mImpl->encodeImpl(*this, *raw_imagep, comment_text, encode_time, mReversible);
|
||||
|
|
@ -337,6 +371,22 @@ BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text,
|
|||
{
|
||||
LLImage::setLastError(mLastError);
|
||||
}
|
||||
|
||||
LLImageCompressionTester* tester = (LLImageCompressionTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
|
||||
if (tester)
|
||||
{
|
||||
// Compression stat gathering
|
||||
// Note that we *do not* take into account the compression failures cases so we night overestimate the time spent processing
|
||||
|
||||
// Always add the compression time to the stat
|
||||
tester->updateCompressionStats(elapsed.getElapsedTimeF32()) ;
|
||||
if (res)
|
||||
{
|
||||
// The whole data stream is finally compressed when res is returned as TRUE
|
||||
tester->updateCompressionStats(this->getDataSize(), raw_imagep->getDataSize()) ;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -540,3 +590,125 @@ void LLImageJ2C::updateRawDiscardLevel()
|
|||
LLImageJ2CImpl::~LLImageJ2CImpl()
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
// Start of LLImageCompressionTester
|
||||
//----------------------------------------------------------------------------------------------
|
||||
LLImageCompressionTester::LLImageCompressionTester() : LLMetricPerformanceTesterBasic(sTesterName)
|
||||
{
|
||||
addMetric("Time Decompression (s)");
|
||||
addMetric("Volume In Decompression (kB)");
|
||||
addMetric("Volume Out Decompression (kB)");
|
||||
addMetric("Decompression Ratio (x:1)");
|
||||
addMetric("Perf Decompression (kB/s)");
|
||||
|
||||
addMetric("Time Compression (s)");
|
||||
addMetric("Volume In Compression (kB)");
|
||||
addMetric("Volume Out Compression (kB)");
|
||||
addMetric("Compression Ratio (x:1)");
|
||||
addMetric("Perf Compression (kB/s)");
|
||||
|
||||
mRunBytesInDecompression = 0;
|
||||
mRunBytesInCompression = 0;
|
||||
|
||||
mTotalBytesInDecompression = 0;
|
||||
mTotalBytesOutDecompression = 0;
|
||||
mTotalBytesInCompression = 0;
|
||||
mTotalBytesOutCompression = 0;
|
||||
|
||||
mTotalTimeDecompression = 0.0f;
|
||||
mTotalTimeCompression = 0.0f;
|
||||
}
|
||||
|
||||
LLImageCompressionTester::~LLImageCompressionTester()
|
||||
{
|
||||
LLImageJ2C::sTesterp = NULL;
|
||||
}
|
||||
|
||||
//virtual
|
||||
void LLImageCompressionTester::outputTestRecord(LLSD *sd)
|
||||
{
|
||||
std::string currentLabel = getCurrentLabelName();
|
||||
|
||||
F32 decompressionPerf = 0.0f;
|
||||
F32 compressionPerf = 0.0f;
|
||||
F32 decompressionRate = 0.0f;
|
||||
F32 compressionRate = 0.0f;
|
||||
|
||||
F32 totalkBInDecompression = (F32)(mTotalBytesInDecompression) / 1000.0;
|
||||
F32 totalkBOutDecompression = (F32)(mTotalBytesOutDecompression) / 1000.0;
|
||||
F32 totalkBInCompression = (F32)(mTotalBytesInCompression) / 1000.0;
|
||||
F32 totalkBOutCompression = (F32)(mTotalBytesOutCompression) / 1000.0;
|
||||
|
||||
if (!is_approx_zero(mTotalTimeDecompression))
|
||||
{
|
||||
decompressionPerf = totalkBInDecompression / mTotalTimeDecompression;
|
||||
}
|
||||
if (!is_approx_zero(totalkBInDecompression))
|
||||
{
|
||||
decompressionRate = totalkBOutDecompression / totalkBInDecompression;
|
||||
}
|
||||
if (!is_approx_zero(mTotalTimeCompression))
|
||||
{
|
||||
compressionPerf = totalkBInCompression / mTotalTimeCompression;
|
||||
}
|
||||
if (!is_approx_zero(totalkBOutCompression))
|
||||
{
|
||||
compressionRate = totalkBInCompression / totalkBOutCompression;
|
||||
}
|
||||
|
||||
(*sd)[currentLabel]["Time Decompression (s)"] = (LLSD::Real)mTotalTimeDecompression;
|
||||
(*sd)[currentLabel]["Volume In Decompression (kB)"] = (LLSD::Real)totalkBInDecompression;
|
||||
(*sd)[currentLabel]["Volume Out Decompression (kB)"]= (LLSD::Real)totalkBOutDecompression;
|
||||
(*sd)[currentLabel]["Decompression Ratio (x:1)"] = (LLSD::Real)decompressionRate;
|
||||
(*sd)[currentLabel]["Perf Decompression (kB/s)"] = (LLSD::Real)decompressionPerf;
|
||||
|
||||
(*sd)[currentLabel]["Time Compression (s)"] = (LLSD::Real)mTotalTimeCompression;
|
||||
(*sd)[currentLabel]["Volume In Compression (kB)"] = (LLSD::Real)totalkBInCompression;
|
||||
(*sd)[currentLabel]["Volume Out Compression (kB)"] = (LLSD::Real)totalkBOutCompression;
|
||||
(*sd)[currentLabel]["Compression Ratio (x:1)"] = (LLSD::Real)compressionRate;
|
||||
(*sd)[currentLabel]["Perf Compression (kB/s)"] = (LLSD::Real)compressionPerf;
|
||||
}
|
||||
|
||||
void LLImageCompressionTester::updateCompressionStats(const F32 deltaTime)
|
||||
{
|
||||
mTotalTimeCompression += deltaTime;
|
||||
}
|
||||
|
||||
void LLImageCompressionTester::updateCompressionStats(const S32 bytesCompress, const S32 bytesRaw)
|
||||
{
|
||||
mTotalBytesInCompression += bytesRaw;
|
||||
mRunBytesInCompression += bytesRaw;
|
||||
mTotalBytesOutCompression += bytesCompress;
|
||||
if (mRunBytesInCompression > (1000000))
|
||||
{
|
||||
// Output everything
|
||||
outputTestResults();
|
||||
// Reset the compression data of the run
|
||||
mRunBytesInCompression = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void LLImageCompressionTester::updateDecompressionStats(const F32 deltaTime)
|
||||
{
|
||||
mTotalTimeDecompression += deltaTime;
|
||||
}
|
||||
|
||||
void LLImageCompressionTester::updateDecompressionStats(const S32 bytesIn, const S32 bytesOut)
|
||||
{
|
||||
mTotalBytesInDecompression += bytesIn;
|
||||
mRunBytesInDecompression += bytesIn;
|
||||
mTotalBytesOutDecompression += bytesOut;
|
||||
if (mRunBytesInDecompression > (1000000))
|
||||
{
|
||||
// Output everything
|
||||
outputTestResults();
|
||||
// Reset the decompression data of the run
|
||||
mRunBytesInDecompression = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
// End of LLTexturePipelineTester
|
||||
//----------------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -29,8 +29,11 @@
|
|||
|
||||
#include "llimage.h"
|
||||
#include "llassettype.h"
|
||||
#include "llmetricperformancetester.h"
|
||||
|
||||
class LLImageJ2CImpl;
|
||||
class LLImageCompressionTester ;
|
||||
|
||||
class LLImageJ2C : public LLImageFormatted
|
||||
{
|
||||
protected:
|
||||
|
|
@ -72,11 +75,12 @@ public:
|
|||
static void openDSO();
|
||||
static void closeDSO();
|
||||
static std::string getEngineInfo();
|
||||
|
||||
|
||||
protected:
|
||||
friend class LLImageJ2CImpl;
|
||||
friend class LLImageJ2COJ;
|
||||
friend class LLImageJ2CKDU;
|
||||
friend class LLImageCompressionTester;
|
||||
void decodeFailed();
|
||||
void updateRawDiscardLevel();
|
||||
|
||||
|
|
@ -90,6 +94,9 @@ protected:
|
|||
BOOL mReversible;
|
||||
LLImageJ2CImpl *mImpl;
|
||||
std::string mLastError;
|
||||
|
||||
// Image compression/decompression tester
|
||||
static LLImageCompressionTester* sTesterp;
|
||||
};
|
||||
|
||||
// Derive from this class to implement JPEG2000 decoding
|
||||
|
|
@ -118,4 +125,40 @@ protected:
|
|||
|
||||
#define LINDEN_J2C_COMMENT_PREFIX "LL_"
|
||||
|
||||
//
|
||||
// This class is used for performance data gathering only.
|
||||
// Tracks the image compression / decompression data,
|
||||
// records and outputs them to the log file.
|
||||
//
|
||||
class LLImageCompressionTester : public LLMetricPerformanceTesterBasic
|
||||
{
|
||||
public:
|
||||
LLImageCompressionTester();
|
||||
~LLImageCompressionTester();
|
||||
|
||||
void updateDecompressionStats(const F32 deltaTime) ;
|
||||
void updateDecompressionStats(const S32 bytesIn, const S32 bytesOut) ;
|
||||
void updateCompressionStats(const F32 deltaTime) ;
|
||||
void updateCompressionStats(const S32 bytesIn, const S32 bytesOut) ;
|
||||
|
||||
protected:
|
||||
/*virtual*/ void outputTestRecord(LLSD* sd);
|
||||
|
||||
private:
|
||||
//
|
||||
// Data size
|
||||
//
|
||||
U32 mTotalBytesInDecompression; // Total bytes fed to decompressor
|
||||
U32 mTotalBytesOutDecompression; // Total bytes produced by decompressor
|
||||
U32 mTotalBytesInCompression; // Total bytes fed to compressor
|
||||
U32 mTotalBytesOutCompression; // Total bytes produced by compressor
|
||||
U32 mRunBytesInDecompression; // Bytes fed to decompressor in this run
|
||||
U32 mRunBytesInCompression; // Bytes fed to compressor in this run
|
||||
//
|
||||
// Time
|
||||
//
|
||||
F32 mTotalTimeDecompression; // Total time spent in computing decompression
|
||||
F32 mTotalTimeCompression; // Total time spent in computing compression
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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,812 @@
|
|||
/**
|
||||
* @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
|
||||
const F64 DEFAULT_DELAY = 120.0; // 2 mintues
|
||||
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})
|
||||
|
|
|
|||
|
|
@ -79,4 +79,6 @@ if (DARWIN)
|
|||
)
|
||||
endif (DARWIN)
|
||||
|
||||
ll_deploy_sharedlibs_command(SLPlugin)
|
||||
if (LL_TESTS)
|
||||
ll_deploy_sharedlibs_command(SLPlugin)
|
||||
endif (LL_TESTS)
|
||||
|
|
|
|||
|
|
@ -610,41 +610,46 @@ void LLGLManager::shutdownGL()
|
|||
void LLGLManager::initExtensions()
|
||||
{
|
||||
#if LL_MESA_HEADLESS
|
||||
# if GL_ARB_multitexture
|
||||
# ifdef GL_ARB_multitexture
|
||||
mHasMultitexture = TRUE;
|
||||
# else
|
||||
mHasMultitexture = FALSE;
|
||||
# endif
|
||||
# if GL_ARB_texture_env_combine
|
||||
# ifdef GL_ARB_texture_env_combine
|
||||
mHasARBEnvCombine = TRUE;
|
||||
# else
|
||||
mHasARBEnvCombine = FALSE;
|
||||
# endif
|
||||
# if GL_ARB_texture_compression
|
||||
# ifdef GL_ARB_texture_compression
|
||||
mHasCompressedTextures = TRUE;
|
||||
# else
|
||||
mHasCompressedTextures = FALSE;
|
||||
# endif
|
||||
# if GL_ARB_vertex_buffer_object
|
||||
# ifdef GL_ARB_vertex_buffer_object
|
||||
mHasVertexBufferObject = TRUE;
|
||||
# else
|
||||
mHasVertexBufferObject = FALSE;
|
||||
# endif
|
||||
# if GL_EXT_framebuffer_object
|
||||
# ifdef GL_EXT_framebuffer_object
|
||||
mHasFramebufferObject = TRUE;
|
||||
# else
|
||||
mHasFramebufferObject = FALSE;
|
||||
# endif
|
||||
# if GL_EXT_framebuffer_multisample
|
||||
# ifdef GL_EXT_framebuffer_multisample
|
||||
mHasFramebufferMultisample = TRUE;
|
||||
# else
|
||||
mHasFramebufferMultisample = FALSE;
|
||||
# endif
|
||||
# if GL_ARB_draw_buffers
|
||||
# ifdef GL_ARB_draw_buffers
|
||||
mHasDrawBuffers = TRUE;
|
||||
#else
|
||||
mHasDrawBuffers = FALSE;
|
||||
# endif
|
||||
# if defined(GL_NV_depth_clamp) || defined(GL_ARB_depth_clamp)
|
||||
mHasDepthClamp = TRUE;
|
||||
#else
|
||||
mHasDepthClamp = FALSE;
|
||||
#endif
|
||||
# if GL_EXT_blend_func_separate
|
||||
mHasBlendFuncSeparate = TRUE;
|
||||
#else
|
||||
|
|
@ -671,6 +676,7 @@ void LLGLManager::initExtensions()
|
|||
mHasCompressedTextures = glh_init_extensions("GL_ARB_texture_compression");
|
||||
mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts);
|
||||
mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts);
|
||||
mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);
|
||||
// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad
|
||||
mHasFramebufferObject = ExtensionExists("GL_EXT_framebuffer_object", gGLHExts.mSysExts)
|
||||
&& ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts);
|
||||
|
|
@ -694,6 +700,7 @@ void LLGLManager::initExtensions()
|
|||
if (getenv("LL_GL_NOEXT"))
|
||||
{
|
||||
//mHasMultitexture = FALSE; // NEEDED!
|
||||
mHasDepthClamp = FALSE;
|
||||
mHasARBEnvCombine = FALSE;
|
||||
mHasCompressedTextures = FALSE;
|
||||
mHasVertexBufferObject = FALSE;
|
||||
|
|
@ -755,6 +762,7 @@ void LLGLManager::initExtensions()
|
|||
if (strchr(blacklist,'s')) mHasFramebufferMultisample = FALSE;
|
||||
if (strchr(blacklist,'t')) mHasTextureRectangle = FALSE;
|
||||
if (strchr(blacklist,'u')) mHasBlendFuncSeparate = FALSE;//S
|
||||
if (strchr(blacklist,'v')) mHasDepthClamp = FALSE;
|
||||
|
||||
}
|
||||
#endif // LL_LINUX || LL_SOLARIS
|
||||
|
|
@ -1047,6 +1055,33 @@ void flush_glerror()
|
|||
glGetError();
|
||||
}
|
||||
|
||||
//this function outputs gl error to the log file, does not crash the code.
|
||||
void log_glerror()
|
||||
{
|
||||
if (LL_UNLIKELY(!gGLManager.mInited))
|
||||
{
|
||||
return ;
|
||||
}
|
||||
// Create or update texture to be used with this data
|
||||
GLenum error;
|
||||
error = glGetError();
|
||||
while (LL_UNLIKELY(error))
|
||||
{
|
||||
GLubyte const * gl_error_msg = gluErrorString(error);
|
||||
if (NULL != gl_error_msg)
|
||||
{
|
||||
llwarns << "GL Error: " << error << " GL Error String: " << gl_error_msg << llendl ;
|
||||
}
|
||||
else
|
||||
{
|
||||
// gluErrorString returns NULL for some extensions' error codes.
|
||||
// you'll probably have to grep for the number in glext.h.
|
||||
llwarns << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << llendl;
|
||||
}
|
||||
error = glGetError();
|
||||
}
|
||||
}
|
||||
|
||||
void do_assert_glerror()
|
||||
{
|
||||
if (LL_UNLIKELY(!gGLManager.mInited))
|
||||
|
|
@ -2037,7 +2072,7 @@ void LLGLDepthTest::checkState()
|
|||
}
|
||||
}
|
||||
|
||||
LLGLClampToFarClip::LLGLClampToFarClip(glh::matrix4f P)
|
||||
LLGLSquashToFarClip::LLGLSquashToFarClip(glh::matrix4f P)
|
||||
{
|
||||
for (U32 i = 0; i < 4; i++)
|
||||
{
|
||||
|
|
@ -2050,7 +2085,7 @@ LLGLClampToFarClip::LLGLClampToFarClip(glh::matrix4f P)
|
|||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
LLGLClampToFarClip::~LLGLClampToFarClip()
|
||||
LLGLSquashToFarClip::~LLGLSquashToFarClip()
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ public:
|
|||
BOOL mHasOcclusionQuery;
|
||||
BOOL mHasPointParameters;
|
||||
BOOL mHasDrawBuffers;
|
||||
BOOL mHasDepthClamp;
|
||||
BOOL mHasTextureRectangle;
|
||||
|
||||
// Other extensions.
|
||||
|
|
@ -157,6 +158,7 @@ void rotate_quat(LLQuaternion& rotation);
|
|||
|
||||
void flush_glerror(); // Flush GL errors when we know we're handling them correctly.
|
||||
|
||||
void log_glerror();
|
||||
void assert_glerror();
|
||||
|
||||
void clear_glerror();
|
||||
|
|
@ -315,11 +317,11 @@ private:
|
|||
leaves this class.
|
||||
Does not stack.
|
||||
*/
|
||||
class LLGLClampToFarClip
|
||||
class LLGLSquashToFarClip
|
||||
{
|
||||
public:
|
||||
LLGLClampToFarClip(glh::matrix4f projection);
|
||||
~LLGLClampToFarClip();
|
||||
LLGLSquashToFarClip(glh::matrix4f projection);
|
||||
~LLGLSquashToFarClip();
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -829,5 +829,15 @@ extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *);
|
|||
|
||||
#endif // LL_MESA / LL_WINDOWS / LL_DARWIN
|
||||
|
||||
// Even when GL_ARB_depth_clamp is available in the driver, the (correct)
|
||||
// headers, and therefore GL_DEPTH_CLAMP might not be defined.
|
||||
// In that case GL_DEPTH_CLAMP_NV should be defined, but why not just
|
||||
// use the known numeric.
|
||||
//
|
||||
// To avoid #ifdef's in the code. Just define this here.
|
||||
#ifndef GL_DEPTH_CLAMP
|
||||
// Probably (still) called GL_DEPTH_CLAMP_NV.
|
||||
#define GL_DEPTH_CLAMP 0x864F
|
||||
#endif
|
||||
|
||||
#endif // LL_LLGLHEADERS_H
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -1057,6 +1069,8 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_
|
|||
checkTexSize(true) ;
|
||||
llcallstacks << fb_x << " : " << fb_y << " : " << x_pos << " : " << y_pos << " : " << width << " : " << height <<
|
||||
" : " << (S32)mComponents << llcallstacksendl ;
|
||||
|
||||
log_glerror() ;
|
||||
}
|
||||
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height);
|
||||
|
|
|
|||
|
|
@ -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) ;
|
||||
|
|
|
|||
|
|
@ -431,6 +431,9 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio
|
|||
if (gGL.mMaxAnisotropy < 1.f)
|
||||
{
|
||||
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gGL.mMaxAnisotropy);
|
||||
|
||||
llinfos << "gGL.mMaxAnisotropy: " << gGL.mMaxAnisotropy << llendl ;
|
||||
gGL.mMaxAnisotropy = llmax(1.f, gGL.mMaxAnisotropy) ;
|
||||
}
|
||||
glTexParameterf(sGLTextureType[mCurrTexType], GL_TEXTURE_MAX_ANISOTROPY_EXT, gGL.mMaxAnisotropy);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
#include "linden_common.h"
|
||||
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
#include "llsys.h"
|
||||
#include "llvertexbuffer.h"
|
||||
// #include "llrender.h"
|
||||
#include "llglheaders.h"
|
||||
|
|
@ -854,6 +854,14 @@ U8* LLVertexBuffer::mapBuffer(S32 access)
|
|||
|
||||
if (!mMappedData)
|
||||
{
|
||||
log_glerror();
|
||||
|
||||
//check the availability of memory
|
||||
U32 avail_phy_mem, avail_vir_mem;
|
||||
LLMemoryInfo::getAvailableMemoryKB(avail_phy_mem, avail_vir_mem) ;
|
||||
llinfos << "Available physical mwmory(KB): " << avail_phy_mem << llendl ;
|
||||
llinfos << "Available virtual memory(KB): " << avail_vir_mem << llendl;
|
||||
|
||||
//--------------------
|
||||
//print out more debug info before crash
|
||||
llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl ;
|
||||
|
|
@ -875,6 +883,8 @@ U8* LLVertexBuffer::mapBuffer(S32 access)
|
|||
|
||||
if (!mMappedIndexData)
|
||||
{
|
||||
log_glerror();
|
||||
|
||||
GLint buff;
|
||||
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
|
||||
if ((GLuint)buff != mGLIndices)
|
||||
|
|
|
|||
|
|
@ -456,8 +456,7 @@ BOOL LLAccordionCtrlTab::handleMouseDown(S32 x, S32 y, MASK mask)
|
|||
{
|
||||
if(y >= (getRect().getHeight() - HEADER_HEIGHT) )
|
||||
{
|
||||
LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
|
||||
header->setFocus(true);
|
||||
mHeader->setFocus(true);
|
||||
changeOpenClose(getDisplayChildren());
|
||||
|
||||
//reset stored state
|
||||
|
|
@ -509,10 +508,9 @@ void LLAccordionCtrlTab::setAccordionView(LLView* panel)
|
|||
|
||||
std::string LLAccordionCtrlTab::getTitle() const
|
||||
{
|
||||
LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
|
||||
if (header)
|
||||
if (mHeader)
|
||||
{
|
||||
return header->getTitle();
|
||||
return mHeader->getTitle();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -522,57 +520,51 @@ std::string LLAccordionCtrlTab::getTitle() const
|
|||
|
||||
void LLAccordionCtrlTab::setTitle(const std::string& title, const std::string& hl)
|
||||
{
|
||||
LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
|
||||
if (header)
|
||||
if (mHeader)
|
||||
{
|
||||
header->setTitle(title, hl);
|
||||
mHeader->setTitle(title, hl);
|
||||
}
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::setTitleFontStyle(std::string style)
|
||||
{
|
||||
LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
|
||||
if (header)
|
||||
if (mHeader)
|
||||
{
|
||||
header->setTitleFontStyle(style);
|
||||
mHeader->setTitleFontStyle(style);
|
||||
}
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::setTitleColor(LLUIColor color)
|
||||
{
|
||||
LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
|
||||
if (header)
|
||||
if (mHeader)
|
||||
{
|
||||
header->setTitleColor(color);
|
||||
mHeader->setTitleColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
boost::signals2::connection LLAccordionCtrlTab::setFocusReceivedCallback(const focus_signal_t::slot_type& cb)
|
||||
{
|
||||
LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
|
||||
if (header)
|
||||
if (mHeader)
|
||||
{
|
||||
return header->setFocusReceivedCallback(cb);
|
||||
return mHeader->setFocusReceivedCallback(cb);
|
||||
}
|
||||
return boost::signals2::connection();
|
||||
}
|
||||
|
||||
boost::signals2::connection LLAccordionCtrlTab::setFocusLostCallback(const focus_signal_t::slot_type& cb)
|
||||
{
|
||||
LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
|
||||
if (header)
|
||||
if (mHeader)
|
||||
{
|
||||
return header->setFocusLostCallback(cb);
|
||||
return mHeader->setFocusLostCallback(cb);
|
||||
}
|
||||
return boost::signals2::connection();
|
||||
}
|
||||
|
||||
void LLAccordionCtrlTab::setSelected(bool is_selected)
|
||||
{
|
||||
LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
|
||||
if (header)
|
||||
if (mHeader)
|
||||
{
|
||||
header->setSelected(is_selected);
|
||||
mHeader->setSelected(is_selected);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -736,6 +728,12 @@ S32 LLAccordionCtrlTab::notifyParent(const LLSD& info)
|
|||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!getDisplayChildren())
|
||||
{
|
||||
// Don't pass scrolling event further if our contents are invisible (STORM-298).
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return LLUICtrl::notifyParent(info);
|
||||
|
|
@ -770,8 +768,7 @@ S32 LLAccordionCtrlTab::notify(const LLSD& info)
|
|||
|
||||
BOOL LLAccordionCtrlTab::handleKey(KEY key, MASK mask, BOOL called_from_parent)
|
||||
{
|
||||
LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
|
||||
if( !header->hasFocus() )
|
||||
if( !mHeader->hasFocus() )
|
||||
return LLUICtrl::handleKey(key, mask, called_from_parent);
|
||||
|
||||
if ( (key == KEY_RETURN )&& mask == MASK_NONE)
|
||||
|
|
@ -824,15 +821,19 @@ BOOL LLAccordionCtrlTab::handleKey(KEY key, MASK mask, BOOL called_from_parent)
|
|||
|
||||
void LLAccordionCtrlTab::showAndFocusHeader()
|
||||
{
|
||||
LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
|
||||
header->setFocus(true);
|
||||
header->setSelected(mSelectionEnabled);
|
||||
mHeader->setFocus(true);
|
||||
mHeader->setSelected(mSelectionEnabled);
|
||||
|
||||
LLRect screen_rc;
|
||||
LLRect selected_rc = header->getRect();
|
||||
LLRect selected_rc = mHeader->getRect();
|
||||
localRectToScreen(selected_rc, &screen_rc);
|
||||
notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue()));
|
||||
|
||||
// This call to notifyParent() is intended to deliver "scrollToShowRect" command
|
||||
// to the parent LLAccordionCtrl so by calling it from the direct parent of this
|
||||
// accordion tab (assuming that the parent is an LLAccordionCtrl) the calls chain
|
||||
// is shortened and messages from inside the collapsed tabs are avoided.
|
||||
// See STORM-536.
|
||||
getParent()->notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue()));
|
||||
}
|
||||
void LLAccordionCtrlTab::storeOpenCloseState()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -61,6 +61,9 @@
|
|||
// use this to control "jumping" behavior when Ctrl-Tabbing
|
||||
const S32 TABBED_FLOATER_OFFSET = 0;
|
||||
|
||||
// static
|
||||
F32 LLFloater::sActiveFloaterTransparency = 0.0f;
|
||||
F32 LLFloater::sInactiveFloaterTransparency = 0.0f;
|
||||
|
||||
std::string LLFloater::sButtonNames[BUTTON_COUNT] =
|
||||
{
|
||||
|
|
@ -200,6 +203,21 @@ void LLFloater::initClass()
|
|||
{
|
||||
sButtonToolTips[i] = LLTrans::getString( sButtonToolTipsIndex[i] );
|
||||
}
|
||||
|
||||
LLControlVariable* ctrl = LLUI::sSettingGroups["config"]->getControl("ActiveFloaterTransparency").get();
|
||||
if (ctrl)
|
||||
{
|
||||
ctrl->getSignal()->connect(boost::bind(&LLFloater::updateActiveFloaterTransparency));
|
||||
sActiveFloaterTransparency = LLUI::sSettingGroups["config"]->getF32("ActiveFloaterTransparency");
|
||||
}
|
||||
|
||||
ctrl = LLUI::sSettingGroups["config"]->getControl("InactiveFloaterTransparency").get();
|
||||
if (ctrl)
|
||||
{
|
||||
ctrl->getSignal()->connect(boost::bind(&LLFloater::updateInactiveFloaterTransparency));
|
||||
sInactiveFloaterTransparency = LLUI::sSettingGroups["config"]->getF32("InactiveFloaterTransparency");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// defaults for floater param block pulled from widgets/floater.xml
|
||||
|
|
@ -232,7 +250,8 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
|
|||
mTornOff(false),
|
||||
mHasBeenDraggedWhileMinimized(FALSE),
|
||||
mPreviousMinimizedBottom(0),
|
||||
mPreviousMinimizedLeft(0)
|
||||
mPreviousMinimizedLeft(0),
|
||||
mMinimizeSignal(NULL)
|
||||
// mNotificationContext(NULL)
|
||||
{
|
||||
mHandle.bind(this);
|
||||
|
|
@ -346,6 +365,18 @@ void LLFloater::layoutDragHandle()
|
|||
updateTitleButtons();
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloater::updateActiveFloaterTransparency()
|
||||
{
|
||||
sActiveFloaterTransparency = LLUI::sSettingGroups["config"]->getF32("ActiveFloaterTransparency");
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloater::updateInactiveFloaterTransparency()
|
||||
{
|
||||
sInactiveFloaterTransparency = LLUI::sSettingGroups["config"]->getF32("InactiveFloaterTransparency");
|
||||
}
|
||||
|
||||
void LLFloater::addResizeCtrls()
|
||||
{
|
||||
// Resize bars (sides)
|
||||
|
|
@ -494,6 +525,8 @@ LLFloater::~LLFloater()
|
|||
setVisible(false); // We're not visible if we're destroyed
|
||||
storeVisibilityControl();
|
||||
storeDockStateControl();
|
||||
|
||||
delete mMinimizeSignal;
|
||||
}
|
||||
|
||||
void LLFloater::storeRectControl()
|
||||
|
|
@ -998,6 +1031,11 @@ void LLFloater::setMinimized(BOOL minimize)
|
|||
|
||||
if (minimize == mMinimized) return;
|
||||
|
||||
if(mMinimizeSignal)
|
||||
{
|
||||
(*mMinimizeSignal)(this, LLSD(minimize));
|
||||
}
|
||||
|
||||
if (minimize)
|
||||
{
|
||||
// minimized flag should be turned on before release focus
|
||||
|
|
@ -1614,7 +1652,8 @@ void LLFloater::onClickCloseBtn()
|
|||
// virtual
|
||||
void LLFloater::draw()
|
||||
{
|
||||
F32 alpha = getDrawContext().mAlpha;
|
||||
mCurrentTransparency = hasFocus() ? sActiveFloaterTransparency : sInactiveFloaterTransparency;
|
||||
|
||||
// draw background
|
||||
if( isBackgroundVisible() )
|
||||
{
|
||||
|
|
@ -1645,12 +1684,12 @@ void LLFloater::draw()
|
|||
if (image)
|
||||
{
|
||||
// We're using images for this floater's backgrounds
|
||||
image->draw(getLocalRect(), overlay_color % alpha);
|
||||
image->draw(getLocalRect(), overlay_color % mCurrentTransparency);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We're not using images, use old-school flat colors
|
||||
gl_rect_2d( left, top, right, bottom, color % alpha );
|
||||
gl_rect_2d( left, top, right, bottom, color % mCurrentTransparency );
|
||||
|
||||
// draw highlight on title bar to indicate focus. RDW
|
||||
if(hasFocus()
|
||||
|
|
@ -1662,7 +1701,7 @@ void LLFloater::draw()
|
|||
const LLFontGL* font = LLFontGL::getFontSansSerif();
|
||||
LLRect r = getRect();
|
||||
gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(), r.getHeight() - (S32)font->getLineHeight() - 1,
|
||||
titlebar_focus_color % alpha, 0, TRUE);
|
||||
titlebar_focus_color % mCurrentTransparency, 0, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1712,7 +1751,6 @@ void LLFloater::draw()
|
|||
|
||||
void LLFloater::drawShadow(LLPanel* panel)
|
||||
{
|
||||
F32 alpha = panel->getDrawContext().mAlpha;
|
||||
S32 left = LLPANEL_BORDER_WIDTH;
|
||||
S32 top = panel->getRect().getHeight() - LLPANEL_BORDER_WIDTH;
|
||||
S32 right = panel->getRect().getWidth() - LLPANEL_BORDER_WIDTH;
|
||||
|
|
@ -1729,7 +1767,7 @@ void LLFloater::drawShadow(LLPanel* panel)
|
|||
shadow_color.mV[VALPHA] *= 0.5f;
|
||||
}
|
||||
gl_drop_shadow(left, top, right, bottom,
|
||||
shadow_color % alpha,
|
||||
shadow_color % mCurrentTransparency,
|
||||
llround(shadow_offset));
|
||||
}
|
||||
|
||||
|
|
@ -2811,6 +2849,12 @@ void LLFloater::initFromParams(const LLFloater::Params& p)
|
|||
}
|
||||
}
|
||||
|
||||
boost::signals2::connection LLFloater::setMinimizeCallback( const commit_signal_t::slot_type& cb )
|
||||
{
|
||||
if (!mMinimizeSignal) mMinimizeSignal = new commit_signal_t();
|
||||
return mMinimizeSignal->connect(cb);
|
||||
}
|
||||
|
||||
LLFastTimer::DeclareTimer POST_BUILD("Floater Post Build");
|
||||
|
||||
bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node)
|
||||
|
|
|
|||
|
|
@ -143,6 +143,8 @@ public:
|
|||
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 );
|
||||
|
||||
void initFromParams(const LLFloater::Params& p);
|
||||
bool initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node = NULL);
|
||||
|
||||
|
|
@ -339,6 +341,9 @@ private:
|
|||
void addDragHandle();
|
||||
void layoutDragHandle(); // repair layout
|
||||
|
||||
static void updateActiveFloaterTransparency();
|
||||
static void updateInactiveFloaterTransparency();
|
||||
|
||||
public:
|
||||
// Called when floater is opened, passes mKey
|
||||
// Public so external views or floaters can watch for this floater opening
|
||||
|
|
@ -348,6 +353,8 @@ public:
|
|||
// Public so external views or floaters can watch for this floater closing
|
||||
commit_signal_t mCloseSignal;
|
||||
|
||||
commit_signal_t* mMinimizeSignal;
|
||||
|
||||
protected:
|
||||
std::string mRectControl;
|
||||
std::string mVisibilityControl;
|
||||
|
|
@ -404,6 +411,11 @@ private:
|
|||
bool mDocked;
|
||||
bool mTornOff;
|
||||
|
||||
F32 mCurrentTransparency;
|
||||
|
||||
static F32 sActiveFloaterTransparency;
|
||||
static F32 sInactiveFloaterTransparency;
|
||||
|
||||
static LLMultiFloater* sHostp;
|
||||
static BOOL sQuitting;
|
||||
static std::string sButtonNames[BUTTON_COUNT];
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
#include "llmenubutton.h"
|
||||
|
||||
// Linden library includes
|
||||
#include "llmenugl.h"
|
||||
#include "lltoggleablemenu.h"
|
||||
#include "llstring.h"
|
||||
#include "v4color.h"
|
||||
|
||||
|
|
@ -44,58 +44,77 @@ LLMenuButton::Params::Params()
|
|||
|
||||
LLMenuButton::LLMenuButton(const LLMenuButton::Params& p)
|
||||
: LLButton(p),
|
||||
mMenu(NULL),
|
||||
mMenuVisibleLastFrame(false)
|
||||
mIsMenuShown(false),
|
||||
mMenuPosition(MP_BOTTOM_LEFT)
|
||||
{
|
||||
std::string menu_filename = p.menu_filename;
|
||||
|
||||
if (!menu_filename.empty())
|
||||
{
|
||||
mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
|
||||
if (!mMenu)
|
||||
LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
|
||||
if (!menu)
|
||||
{
|
||||
llwarns << "Error loading menu_button menu" << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2));
|
||||
|
||||
mMenuHandle = menu->getHandle();
|
||||
|
||||
updateMenuOrigin();
|
||||
}
|
||||
}
|
||||
|
||||
void LLMenuButton::toggleMenu()
|
||||
boost::signals2::connection LLMenuButton::setMouseDownCallback( const mouse_signal_t::slot_type& cb )
|
||||
{
|
||||
if(!mMenu)
|
||||
return;
|
||||
return LLUICtrl::setMouseDownCallback(cb);
|
||||
}
|
||||
|
||||
if (mMenu->getVisible() || mMenuVisibleLastFrame)
|
||||
void LLMenuButton::hideMenu()
|
||||
{
|
||||
if(mMenuHandle.isDead()) return;
|
||||
|
||||
LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
|
||||
if (menu)
|
||||
{
|
||||
mMenu->setVisible(FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLRect rect = getRect();
|
||||
//mMenu->needsArrange(); //so it recalculates the visible elements
|
||||
LLMenuGL::showPopup(getParent(), mMenu, rect.mLeft, rect.mBottom);
|
||||
menu->setVisible(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLMenuButton::hideMenu()
|
||||
{
|
||||
if(!mMenu)
|
||||
return;
|
||||
mMenu->setVisible(FALSE);
|
||||
LLToggleableMenu* LLMenuButton::getMenu()
|
||||
{
|
||||
return dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
|
||||
}
|
||||
|
||||
void LLMenuButton::setMenu(LLToggleableMenu* menu, EMenuPosition position /*MP_TOP_LEFT*/)
|
||||
{
|
||||
if (!menu) return;
|
||||
|
||||
mMenuHandle = menu->getHandle();
|
||||
mMenuPosition = position;
|
||||
|
||||
menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2));
|
||||
}
|
||||
|
||||
BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask )
|
||||
{
|
||||
if (mMenuHandle.isDead()) return FALSE;
|
||||
|
||||
if( KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key))
|
||||
{
|
||||
// *HACK: We emit the mouse down signal to fire the callback bound to the
|
||||
// menu emerging event before actually displaying the menu. See STORM-263.
|
||||
LLUICtrl::handleMouseDown(-1, -1, MASK_NONE);
|
||||
|
||||
toggleMenu();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (mMenu && mMenu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE)
|
||||
LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
|
||||
if (menu && menu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE)
|
||||
{
|
||||
mMenu->setVisible(FALSE);
|
||||
menu->setVisible(FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -104,34 +123,77 @@ BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask )
|
|||
|
||||
BOOL LLMenuButton::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
if (hasTabStop() && !getIsChrome())
|
||||
{
|
||||
setFocus(TRUE);
|
||||
}
|
||||
LLButton::handleMouseDown(x, y, mask);
|
||||
|
||||
toggleMenu();
|
||||
|
||||
if (getSoundFlags() & MOUSE_DOWN)
|
||||
{
|
||||
make_ui_sound("UISndClick");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LLMenuButton::draw()
|
||||
void LLMenuButton::toggleMenu()
|
||||
{
|
||||
//we save this off so next frame when we try to close it by
|
||||
//button click, and it hides menus before we get to it, we know
|
||||
mMenuVisibleLastFrame = mMenu && mMenu->getVisible();
|
||||
|
||||
if (mMenuVisibleLastFrame)
|
||||
if(mMenuHandle.isDead()) return;
|
||||
|
||||
LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
|
||||
if (!menu) return;
|
||||
|
||||
// Store the button rectangle to toggle menu visibility if a mouse event
|
||||
// occurred inside or outside the button rect.
|
||||
menu->setButtonRect(this);
|
||||
|
||||
if (!menu->toggleVisibility() && mIsMenuShown)
|
||||
{
|
||||
setForcePressedState(true);
|
||||
setForcePressedState(false);
|
||||
mIsMenuShown = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
menu->buildDrawLabels();
|
||||
menu->arrangeAndClear();
|
||||
menu->updateParent(LLMenuGL::sMenuContainer);
|
||||
|
||||
LLButton::draw();
|
||||
updateMenuOrigin();
|
||||
|
||||
setForcePressedState(false);
|
||||
LLMenuGL::showPopup(getParent(), menu, mX, mY);
|
||||
|
||||
setForcePressedState(true);
|
||||
mIsMenuShown = true;
|
||||
}
|
||||
}
|
||||
|
||||
void LLMenuButton::updateMenuOrigin()
|
||||
{
|
||||
if (mMenuHandle.isDead()) return;
|
||||
|
||||
LLRect rect = getRect();
|
||||
|
||||
switch (mMenuPosition)
|
||||
{
|
||||
case MP_TOP_LEFT:
|
||||
{
|
||||
mX = rect.mLeft;
|
||||
mY = rect.mTop + mMenuHandle.get()->getRect().getHeight();
|
||||
break;
|
||||
}
|
||||
case MP_BOTTOM_LEFT:
|
||||
{
|
||||
mX = rect.mLeft;
|
||||
mY = rect.mBottom;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLMenuButton::onMenuVisibilityChange(const LLSD& param)
|
||||
{
|
||||
bool new_visibility = param["visibility"].asBoolean();
|
||||
bool is_closed_by_button_click = param["closed_by_button_click"].asBoolean();
|
||||
|
||||
// Reset the button "pressed" state only if the menu is shown by this particular
|
||||
// menu button (not any other control) and is not being closed by a click on the button.
|
||||
if (!new_visibility && !is_closed_by_button_click && mIsMenuShown)
|
||||
{
|
||||
setForcePressedState(false);
|
||||
mIsMenuShown = false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
#include "llbutton.h"
|
||||
|
||||
class LLMenuGL;
|
||||
class LLToggleableMenu;
|
||||
|
||||
class LLMenuButton
|
||||
: public LLButton
|
||||
|
|
@ -42,22 +42,41 @@ public:
|
|||
Optional<std::string> menu_filename;
|
||||
|
||||
Params();
|
||||
};
|
||||
};
|
||||
|
||||
typedef enum e_menu_position
|
||||
{
|
||||
MP_TOP_LEFT,
|
||||
MP_BOTTOM_LEFT
|
||||
} EMenuPosition;
|
||||
|
||||
void toggleMenu();
|
||||
/*virtual*/ void draw();
|
||||
boost::signals2::connection setMouseDownCallback( const mouse_signal_t::slot_type& cb );
|
||||
|
||||
/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask );
|
||||
|
||||
void hideMenu();
|
||||
LLMenuGL* getMenu() { return mMenu; }
|
||||
|
||||
LLToggleableMenu* getMenu();
|
||||
void setMenu(LLToggleableMenu* menu, EMenuPosition position = MP_TOP_LEFT);
|
||||
|
||||
void setMenuPosition(EMenuPosition position) { mMenuPosition = position; }
|
||||
|
||||
protected:
|
||||
friend class LLUICtrlFactory;
|
||||
LLMenuButton(const Params&);
|
||||
|
||||
void toggleMenu();
|
||||
void updateMenuOrigin();
|
||||
|
||||
void onMenuVisibilityChange(const LLSD& param);
|
||||
|
||||
private:
|
||||
LLMenuGL* mMenu;
|
||||
bool mMenuVisibleLastFrame;
|
||||
LLHandle<LLView> mMenuHandle;
|
||||
bool mIsMenuShown;
|
||||
EMenuPosition mMenuPosition;
|
||||
S32 mX;
|
||||
S32 mY;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1848,89 +1848,104 @@ BOOL LLMenuGL::isOpen()
|
|||
}
|
||||
}
|
||||
|
||||
void LLMenuGL::scrollItemsUp()
|
||||
|
||||
|
||||
bool LLMenuGL::scrollItems(EScrollingDirection direction)
|
||||
{
|
||||
// Slowing down the items scrolling when arrow button is held
|
||||
// Slowing down items scrolling when arrow button is held
|
||||
if (mScrollItemsTimer.hasExpired() && NULL != mFirstVisibleItem)
|
||||
{
|
||||
mScrollItemsTimer.setTimerExpirySec(.033f);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
item_list_t::iterator cur_item_iter;
|
||||
item_list_t::iterator prev_item_iter;
|
||||
for (cur_item_iter = mItems.begin(), prev_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++)
|
||||
switch (direction)
|
||||
{
|
||||
if( (*cur_item_iter) == mFirstVisibleItem)
|
||||
case SD_UP:
|
||||
{
|
||||
item_list_t::iterator cur_item_iter;
|
||||
item_list_t::iterator prev_item_iter;
|
||||
for (cur_item_iter = mItems.begin(), prev_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++)
|
||||
{
|
||||
break;
|
||||
if( (*cur_item_iter) == mFirstVisibleItem)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if ((*cur_item_iter)->getVisible())
|
||||
{
|
||||
prev_item_iter = cur_item_iter;
|
||||
}
|
||||
}
|
||||
if ((*cur_item_iter)->getVisible())
|
||||
|
||||
if ((*prev_item_iter)->getVisible())
|
||||
{
|
||||
prev_item_iter = cur_item_iter;
|
||||
mFirstVisibleItem = *prev_item_iter;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ((*prev_item_iter)->getVisible())
|
||||
case SD_DOWN:
|
||||
{
|
||||
mFirstVisibleItem = *prev_item_iter;
|
||||
}
|
||||
|
||||
mNeedsArrange = TRUE;
|
||||
arrangeAndClear();
|
||||
}
|
||||
|
||||
void LLMenuGL::scrollItemsDown()
|
||||
{
|
||||
// Slowing down the items scrolling when arrow button is held
|
||||
if (mScrollItemsTimer.hasExpired())
|
||||
{
|
||||
mScrollItemsTimer.setTimerExpirySec(.033f);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (NULL == mFirstVisibleItem)
|
||||
{
|
||||
mFirstVisibleItem = *mItems.begin();
|
||||
}
|
||||
|
||||
item_list_t::iterator cur_item_iter;
|
||||
|
||||
for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++)
|
||||
{
|
||||
if( (*cur_item_iter) == mFirstVisibleItem)
|
||||
if (NULL == mFirstVisibleItem)
|
||||
{
|
||||
break;
|
||||
mFirstVisibleItem = *mItems.begin();
|
||||
}
|
||||
}
|
||||
|
||||
item_list_t::iterator next_item_iter;
|
||||
item_list_t::iterator cur_item_iter;
|
||||
|
||||
if (cur_item_iter != mItems.end())
|
||||
{
|
||||
for (next_item_iter = ++cur_item_iter; next_item_iter != mItems.end(); next_item_iter++)
|
||||
for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++)
|
||||
{
|
||||
if( (*next_item_iter)->getVisible())
|
||||
if( (*cur_item_iter) == mFirstVisibleItem)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (next_item_iter != mItems.end() &&
|
||||
(*next_item_iter)->getVisible())
|
||||
|
||||
item_list_t::iterator next_item_iter;
|
||||
|
||||
if (cur_item_iter != mItems.end())
|
||||
{
|
||||
mFirstVisibleItem = *next_item_iter;
|
||||
for (next_item_iter = ++cur_item_iter; next_item_iter != mItems.end(); next_item_iter++)
|
||||
{
|
||||
if( (*next_item_iter)->getVisible())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (next_item_iter != mItems.end() &&
|
||||
(*next_item_iter)->getVisible())
|
||||
{
|
||||
mFirstVisibleItem = *next_item_iter;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SD_BEGIN:
|
||||
{
|
||||
mFirstVisibleItem = *mItems.begin();
|
||||
break;
|
||||
}
|
||||
case SD_END:
|
||||
{
|
||||
item_list_t::reverse_iterator first_visible_item_iter = mItems.rend();
|
||||
|
||||
// Advance by mMaxScrollableItems back from the end of the list
|
||||
// to make the last item visible.
|
||||
std::advance(first_visible_item_iter, mMaxScrollableItems);
|
||||
mFirstVisibleItem = *first_visible_item_iter;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
llwarns << "Unknown scrolling direction: " << direction << llendl;
|
||||
}
|
||||
|
||||
mNeedsArrange = TRUE;
|
||||
arrangeAndClear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// rearrange the child rects so they fit the shape of the menu.
|
||||
|
|
@ -2162,7 +2177,7 @@ void LLMenuGL::arrange( void )
|
|||
LLMenuScrollItem::Params item_params;
|
||||
item_params.name(ARROW_UP);
|
||||
item_params.arrow_type(LLMenuScrollItem::ARROW_UP);
|
||||
item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItemsUp, this));
|
||||
item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItems, this, SD_UP));
|
||||
|
||||
mArrowUpItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params);
|
||||
LLUICtrl::addChild(mArrowUpItem);
|
||||
|
|
@ -2173,7 +2188,7 @@ void LLMenuGL::arrange( void )
|
|||
LLMenuScrollItem::Params item_params;
|
||||
item_params.name(ARROW_DOWN);
|
||||
item_params.arrow_type(LLMenuScrollItem::ARROW_DOWN);
|
||||
item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItemsDown, this));
|
||||
item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItems, this, SD_DOWN));
|
||||
|
||||
mArrowDownItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params);
|
||||
LLUICtrl::addChild(mArrowDownItem);
|
||||
|
|
@ -2603,14 +2618,8 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa
|
|||
((LLFloater*)getParent())->setFocus(TRUE);
|
||||
}
|
||||
|
||||
item_list_t::iterator cur_item_iter;
|
||||
for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); ++cur_item_iter)
|
||||
{
|
||||
if( (*cur_item_iter) == cur_item)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Current item position in the items list
|
||||
item_list_t::iterator cur_item_iter = std::find(mItems.begin(), mItems.end(), cur_item);
|
||||
|
||||
item_list_t::iterator next_item_iter;
|
||||
if (cur_item_iter == mItems.end())
|
||||
|
|
@ -2621,9 +2630,37 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa
|
|||
{
|
||||
next_item_iter = cur_item_iter;
|
||||
next_item_iter++;
|
||||
|
||||
// First visible item position in the items list
|
||||
item_list_t::iterator first_visible_item_iter = std::find(mItems.begin(), mItems.end(), mFirstVisibleItem);
|
||||
|
||||
if (next_item_iter == mItems.end())
|
||||
{
|
||||
next_item_iter = mItems.begin();
|
||||
|
||||
// If current item is the last in the list, the menu is scrolled to the beginning
|
||||
// and the first item is highlighted.
|
||||
if (mScrollable && !scrollItems(SD_BEGIN))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
// If current item is the last visible, the menu is scrolled one item down
|
||||
// and the next item is highlighted.
|
||||
else if (mScrollable &&
|
||||
(U32)std::abs(std::distance(first_visible_item_iter, next_item_iter)) >= mMaxScrollableItems)
|
||||
{
|
||||
// Call highlightNextItem() recursively only if the menu was successfully scrolled down.
|
||||
// If scroll timer hasn't expired yet the menu won't be scrolled and calling
|
||||
// highlightNextItem() will result in an endless recursion.
|
||||
if (scrollItems(SD_DOWN))
|
||||
{
|
||||
return highlightNextItem(cur_item, skip_disabled);
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2681,14 +2718,8 @@ LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disa
|
|||
((LLFloater*)getParent())->setFocus(TRUE);
|
||||
}
|
||||
|
||||
item_list_t::reverse_iterator cur_item_iter;
|
||||
for (cur_item_iter = mItems.rbegin(); cur_item_iter != mItems.rend(); ++cur_item_iter)
|
||||
{
|
||||
if( (*cur_item_iter) == cur_item)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Current item reverse position from the end of the list
|
||||
item_list_t::reverse_iterator cur_item_iter = std::find(mItems.rbegin(), mItems.rend(), cur_item);
|
||||
|
||||
item_list_t::reverse_iterator prev_item_iter;
|
||||
if (cur_item_iter == mItems.rend())
|
||||
|
|
@ -2699,9 +2730,37 @@ LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disa
|
|||
{
|
||||
prev_item_iter = cur_item_iter;
|
||||
prev_item_iter++;
|
||||
|
||||
// First visible item reverse position in the items list
|
||||
item_list_t::reverse_iterator first_visible_item_iter = std::find(mItems.rbegin(), mItems.rend(), mFirstVisibleItem);
|
||||
|
||||
if (prev_item_iter == mItems.rend())
|
||||
{
|
||||
prev_item_iter = mItems.rbegin();
|
||||
|
||||
// If current item is the first in the list, the menu is scrolled to the end
|
||||
// and the last item is highlighted.
|
||||
if (mScrollable && !scrollItems(SD_END))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
// If current item is the first visible, the menu is scrolled one item up
|
||||
// and the previous item is highlighted.
|
||||
else if (mScrollable &&
|
||||
std::distance(first_visible_item_iter, cur_item_iter) <= 0)
|
||||
{
|
||||
// Call highlightNextItem() only if the menu was successfully scrolled up.
|
||||
// If scroll timer hasn't expired yet the menu won't be scrolled and calling
|
||||
// highlightNextItem() will result in an endless recursion.
|
||||
if (scrollItems(SD_UP))
|
||||
{
|
||||
return highlightPrevItem(cur_item, skip_disabled);
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2872,12 +2931,12 @@ BOOL LLMenuGL::handleScrollWheel( S32 x, S32 y, S32 clicks )
|
|||
if( clicks > 0 )
|
||||
{
|
||||
while( clicks-- )
|
||||
scrollItemsDown();
|
||||
scrollItems(SD_DOWN);
|
||||
}
|
||||
else
|
||||
{
|
||||
while( clicks++ )
|
||||
scrollItemsUp();
|
||||
scrollItems(SD_UP);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
|
|
|||
|
|
@ -397,6 +397,15 @@ public:
|
|||
static const std::string ARROW_UP;
|
||||
static const std::string ARROW_DOWN;
|
||||
|
||||
// for scrollable menus
|
||||
typedef enum e_scrolling_direction
|
||||
{
|
||||
SD_UP = 0,
|
||||
SD_DOWN = 1,
|
||||
SD_BEGIN = 2,
|
||||
SD_END = 3
|
||||
} EScrollingDirection;
|
||||
|
||||
protected:
|
||||
LLMenuGL(const LLMenuGL::Params& p);
|
||||
friend class LLUICtrlFactory;
|
||||
|
|
@ -503,8 +512,7 @@ public:
|
|||
|
||||
S32 getShortcutPad() { return mShortcutPad; }
|
||||
|
||||
void scrollItemsUp();
|
||||
void scrollItemsDown();
|
||||
bool scrollItems(EScrollingDirection direction);
|
||||
BOOL isScrollable() const { return mScrollable; }
|
||||
|
||||
static class LLMenuHolderGL* sMenuContainer;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@
|
|||
#include "llnotifications.h"
|
||||
#include "llnotificationtemplate.h"
|
||||
|
||||
#include "llavatarnamecache.h"
|
||||
#include "llinstantmessage.h"
|
||||
#include "llcachename.h"
|
||||
#include "llxmlnode.h"
|
||||
#include "lluictrl.h"
|
||||
#include "lluictrlfactory.h"
|
||||
|
|
@ -62,7 +64,7 @@ LLNotificationForm::FormElementBase::FormElementBase()
|
|||
LLNotificationForm::FormIgnore::FormIgnore()
|
||||
: text("text"),
|
||||
control("control"),
|
||||
invert_control("invert_control", true),
|
||||
invert_control("invert_control", false),
|
||||
save_option("save_option", false)
|
||||
{}
|
||||
|
||||
|
|
@ -79,7 +81,9 @@ LLNotificationForm::FormButton::FormButton()
|
|||
|
||||
LLNotificationForm::FormInput::FormInput()
|
||||
: type("type"),
|
||||
width("width", 0)
|
||||
max_length_chars("max_length_chars"),
|
||||
width("width", 0),
|
||||
value("value")
|
||||
{}
|
||||
|
||||
LLNotificationForm::FormElement::FormElement()
|
||||
|
|
@ -190,7 +194,7 @@ LLNotificationForm::LLNotificationForm()
|
|||
|
||||
LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotificationForm::Params& p)
|
||||
: mIgnore(IGNORE_NO),
|
||||
mInvertSetting(true) // ignore settings by default mean true=show, false=ignore
|
||||
mInvertSetting(false) // ignore settings by default mean true=show, false=ignore
|
||||
{
|
||||
if (p.ignore.isProvided())
|
||||
{
|
||||
|
|
@ -215,7 +219,7 @@ LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotifica
|
|||
}
|
||||
else
|
||||
{
|
||||
LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Ignore notification with this name", TRUE);
|
||||
LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Show notification with this name", TRUE);
|
||||
mIgnoreSetting = LLUI::sSettingGroups["ignores"]->getControl(name);
|
||||
}
|
||||
}
|
||||
|
|
@ -353,15 +357,15 @@ LLControlVariablePtr LLNotificationForm::getIgnoreSetting()
|
|||
|
||||
bool LLNotificationForm::getIgnored()
|
||||
{
|
||||
bool ignored = false;
|
||||
bool show = true;
|
||||
if (mIgnore != LLNotificationForm::IGNORE_NO
|
||||
&& mIgnoreSetting)
|
||||
{
|
||||
ignored = mIgnoreSetting->getValue().asBoolean();
|
||||
if (mInvertSetting) ignored = !ignored;
|
||||
show = mIgnoreSetting->getValue().asBoolean();
|
||||
if (mInvertSetting) show = !show;
|
||||
}
|
||||
|
||||
return ignored;
|
||||
return !show;
|
||||
}
|
||||
|
||||
void LLNotificationForm::setIgnored(bool ignored)
|
||||
|
|
@ -369,7 +373,7 @@ void LLNotificationForm::setIgnored(bool ignored)
|
|||
if (mIgnoreSetting)
|
||||
{
|
||||
if (mInvertSetting) ignored = !ignored;
|
||||
mIgnoreSetting->setValue(ignored);
|
||||
mIgnoreSetting->setValue(!ignored);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1552,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,8 +98,8 @@
|
|||
#include "llinitparam.h"
|
||||
#include "llnotificationslistener.h"
|
||||
#include "llnotificationptr.h"
|
||||
#include "llcachename.h"
|
||||
|
||||
class LLAvatarName;
|
||||
typedef enum e_notification_priority
|
||||
{
|
||||
NOTIFICATION_PRIORITY_UNSPECIFIED,
|
||||
|
|
@ -194,7 +194,9 @@ public:
|
|||
{
|
||||
Mandatory<std::string> type;
|
||||
Optional<S32> width;
|
||||
Optional<S32> max_length_chars;
|
||||
|
||||
Optional<std::string> value;
|
||||
FormInput();
|
||||
};
|
||||
|
||||
|
|
@ -973,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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -904,7 +904,7 @@ LLPanel *LLPanel::childGetVisiblePanelWithHelp()
|
|||
child = *it;
|
||||
// do we have a panel with a help topic?
|
||||
LLPanel *panel = dynamic_cast<LLPanel *>(child);
|
||||
if (panel && panel->getVisible() && !panel->getHelpTopic().empty())
|
||||
if (panel && panel->isInVisibleChain() && !panel->getHelpTopic().empty())
|
||||
{
|
||||
return panel;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -1605,28 +1605,39 @@ 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);
|
||||
style_params.fillFrom(getDefaultStyleParams());
|
||||
|
||||
S32 part = (S32)LLTextParser::WHOLE;
|
||||
if(mParseHTML)
|
||||
if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358).
|
||||
{
|
||||
S32 start=0,end=0;
|
||||
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)
|
||||
|
|
@ -1647,26 +1658,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())
|
||||
{
|
||||
|
|
@ -1851,8 +1856,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();
|
||||
|
|
@ -1873,7 +1879,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();
|
||||
|
|
@ -1882,6 +1888,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();
|
||||
}
|
||||
|
|
@ -1979,8 +2000,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;
|
||||
|
|
@ -2196,19 +2217,39 @@ bool LLTextBase::scrolledToEnd()
|
|||
return mScroller->isAtBottom();
|
||||
}
|
||||
|
||||
|
||||
bool LLTextBase::setCursor(S32 row, S32 column)
|
||||
{
|
||||
if (0 <= row && row < (S32)mLineInfoList.size())
|
||||
{
|
||||
S32 doc_pos = mLineInfoList[row].mDocIndexStart;
|
||||
column = llclamp(column, 0, mLineInfoList[row].mDocIndexEnd - mLineInfoList[row].mDocIndexStart - 1);
|
||||
doc_pos += column;
|
||||
updateCursorXPos();
|
||||
if (row < 0 || column < 0) return false;
|
||||
|
||||
S32 n_lines = mLineInfoList.size();
|
||||
for (S32 line = row; line < n_lines; ++line)
|
||||
{
|
||||
const line_info& li = mLineInfoList[line];
|
||||
|
||||
if (li.mLineNum < row)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (li.mLineNum > row)
|
||||
{
|
||||
break; // invalid column specified
|
||||
}
|
||||
|
||||
// Found the given row.
|
||||
S32 line_length = li.mDocIndexEnd - li.mDocIndexStart;;
|
||||
if (column >= line_length)
|
||||
{
|
||||
column -= line_length;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Found the given column.
|
||||
updateCursorXPos();
|
||||
S32 doc_pos = li.mDocIndexStart + column;
|
||||
return setCursorPos(doc_pos);
|
||||
}
|
||||
return false;
|
||||
|
||||
return false; // invalid row or column specified
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -493,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);
|
||||
|
|
|
|||
|
|
@ -35,10 +35,22 @@ static LLDefaultChildRegistry::Register<LLToggleableMenu> r("toggleable_menu");
|
|||
LLToggleableMenu::LLToggleableMenu(const LLToggleableMenu::Params& p)
|
||||
: LLMenuGL(p),
|
||||
mButtonRect(),
|
||||
mVisibilityChangeSignal(NULL),
|
||||
mClosedByButtonClick(false)
|
||||
{
|
||||
}
|
||||
|
||||
LLToggleableMenu::~LLToggleableMenu()
|
||||
{
|
||||
delete mVisibilityChangeSignal;
|
||||
}
|
||||
|
||||
boost::signals2::connection LLToggleableMenu::setVisibilityChangeCallback(const commit_signal_t::slot_type& cb)
|
||||
{
|
||||
if (!mVisibilityChangeSignal) mVisibilityChangeSignal = new commit_signal_t();
|
||||
return mVisibilityChangeSignal->connect(cb);
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLToggleableMenu::handleVisibilityChange (BOOL curVisibilityIn)
|
||||
{
|
||||
|
|
@ -49,6 +61,12 @@ void LLToggleableMenu::handleVisibilityChange (BOOL curVisibilityIn)
|
|||
{
|
||||
mClosedByButtonClick = true;
|
||||
}
|
||||
|
||||
if (mVisibilityChangeSignal)
|
||||
{
|
||||
(*mVisibilityChangeSignal)(this,
|
||||
LLSD().with("visibility", curVisibilityIn).with("closed_by_button_click", mClosedByButtonClick));
|
||||
}
|
||||
}
|
||||
|
||||
void LLToggleableMenu::setButtonRect(const LLRect& rect, LLView* current_view)
|
||||
|
|
|
|||
|
|
@ -41,6 +41,10 @@ protected:
|
|||
LLToggleableMenu(const Params&);
|
||||
friend class LLUICtrlFactory;
|
||||
public:
|
||||
~LLToggleableMenu();
|
||||
|
||||
boost::signals2::connection setVisibilityChangeCallback( const commit_signal_t::slot_type& cb );
|
||||
|
||||
virtual void handleVisibilityChange (BOOL curVisibilityIn);
|
||||
|
||||
const LLRect& getButtonRect() const { return mButtonRect; }
|
||||
|
|
@ -57,6 +61,7 @@ public:
|
|||
protected:
|
||||
bool mClosedByButtonClick;
|
||||
LLRect mButtonRect;
|
||||
commit_signal_t* mVisibilityChangeSignal;
|
||||
};
|
||||
|
||||
#endif // LL_LLTOGGLEABLEMENU_H
|
||||
|
|
|
|||
|
|
@ -58,10 +58,12 @@ class LLUIString
|
|||
public:
|
||||
// These methods all perform appropriate argument substitution
|
||||
// and modify mOrig where appropriate
|
||||
LLUIString() : mArgs(NULL), 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) : mArgs(NULL) { assign(instring); }
|
||||
|
||||
~LLUIString() { delete mArgs; }
|
||||
|
||||
void assign(const std::string& instring);
|
||||
LLUIString& operator=(const std::string& s) { assign(s); return *this; }
|
||||
|
||||
|
|
@ -81,14 +83,14 @@ public:
|
|||
|
||||
void 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
|
||||
void truncate(S32 maxchars);
|
||||
void erase(S32 charidx, S32 len);
|
||||
void insert(S32 charidx, const LLWString& wchars);
|
||||
void replace(S32 charidx, llwchar wc);
|
||||
|
||||
|
||||
private:
|
||||
// something changed, requiring reformatting of strings
|
||||
void dirty();
|
||||
|
|
@ -100,7 +102,7 @@ private:
|
|||
void updateResult() const;
|
||||
void updateWResult() const;
|
||||
LLStringUtil::format_map_t& getArgs();
|
||||
|
||||
|
||||
std::string mOrig;
|
||||
mutable std::string mResult;
|
||||
mutable LLWString mWResult; // for displaying
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -789,9 +978,8 @@ std::string LLUrlEntryWorldMap::getLocation(const std::string &url) const
|
|||
//
|
||||
LLUrlEntryNoLink::LLUrlEntryNoLink()
|
||||
{
|
||||
mPattern = boost::regex("<nolink>[^<]*</nolink>",
|
||||
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,13 @@ std::string LLUrlEntryNoLink::getLabel(const std::string &url, const LLUrlLabelC
|
|||
return getUrl(url);
|
||||
}
|
||||
|
||||
LLStyle::Params LLUrlEntryNoLink::getStyle() const
|
||||
{
|
||||
// Don't render as URL (i.e. no context menu or hand cursor).
|
||||
return LLStyle::Params().is_link(false);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// LLUrlEntryIcon describes an icon with <icon>...</icon> tags
|
||||
//
|
||||
|
|
@ -812,7 +1007,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 boost::signals2::trackable
|
||||
{
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "llurlentry_stub.cpp"
|
||||
#include "lltut.h"
|
||||
#include "../lluicolortable.h"
|
||||
#include "../lluiimage.h"
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
|
|
@ -40,6 +41,26 @@ LLUIColor LLUIColorTable::getColor(const std::string& name, const LLColor4& defa
|
|||
|
||||
LLUIColor::LLUIColor() : mColorPtr(NULL) {}
|
||||
|
||||
LLUIImage::LLUIImage(const std::string& name, LLPointer<LLTexture> image)
|
||||
{
|
||||
}
|
||||
|
||||
LLUIImage::~LLUIImage()
|
||||
{
|
||||
}
|
||||
|
||||
//virtual
|
||||
S32 LLUIImage::getWidth() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//virtual
|
||||
S32 LLUIImage::getHeight() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace tut
|
||||
{
|
||||
struct LLUrlEntryData
|
||||
|
|
|
|||
|
|
@ -25,14 +25,135 @@
|
|||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "../llurlmatch.h"
|
||||
#include "../lluiimage.h"
|
||||
#include "lltut.h"
|
||||
|
||||
// link seam
|
||||
// link seams
|
||||
|
||||
LLUIColor::LLUIColor()
|
||||
: mColorPtr(NULL)
|
||||
{}
|
||||
|
||||
LLStyle::Params::Params()
|
||||
{
|
||||
}
|
||||
|
||||
LLUIImage::LLUIImage(const std::string& name, LLPointer<LLTexture> image)
|
||||
{
|
||||
}
|
||||
|
||||
LLUIImage::~LLUIImage()
|
||||
{
|
||||
}
|
||||
|
||||
//virtual
|
||||
S32 LLUIImage::getWidth() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//virtual
|
||||
S32 LLUIImage::getHeight() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace LLInitParam
|
||||
{
|
||||
BaseBlock::BaseBlock() {}
|
||||
BaseBlock::~BaseBlock() {}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
namespace tut
|
||||
{
|
||||
struct LLUrlMatchData
|
||||
|
|
@ -59,7 +180,7 @@ namespace tut
|
|||
LLUrlMatch match;
|
||||
ensure("empty()", match.empty());
|
||||
|
||||
match.setValues(0, 1, "http://secondlife.com", "Second Life", "", "", LLUIColor(), "", "", false,LLUUID::null);
|
||||
match.setValues(0, 1, "http://secondlife.com", "Second Life", "", "", LLStyle::Params(), "", "", LLUUID::null);
|
||||
ensure("! empty()", ! match.empty());
|
||||
}
|
||||
|
||||
|
|
@ -72,7 +193,7 @@ namespace tut
|
|||
LLUrlMatch match;
|
||||
ensure_equals("getStart() == 0", match.getStart(), 0);
|
||||
|
||||
match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
|
||||
match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
|
||||
ensure_equals("getStart() == 10", match.getStart(), 10);
|
||||
}
|
||||
|
||||
|
|
@ -85,7 +206,7 @@ namespace tut
|
|||
LLUrlMatch match;
|
||||
ensure_equals("getEnd() == 0", match.getEnd(), 0);
|
||||
|
||||
match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
|
||||
match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
|
||||
ensure_equals("getEnd() == 20", match.getEnd(), 20);
|
||||
}
|
||||
|
||||
|
|
@ -98,10 +219,10 @@ namespace tut
|
|||
LLUrlMatch match;
|
||||
ensure_equals("getUrl() == ''", match.getUrl(), "");
|
||||
|
||||
match.setValues(10, 20, "http://slurl.com/", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
|
||||
match.setValues(10, 20, "http://slurl.com/", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
|
||||
ensure_equals("getUrl() == 'http://slurl.com/'", match.getUrl(), "http://slurl.com/");
|
||||
|
||||
match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
|
||||
match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
|
||||
ensure_equals("getUrl() == '' (2)", match.getUrl(), "");
|
||||
}
|
||||
|
||||
|
|
@ -114,10 +235,10 @@ namespace tut
|
|||
LLUrlMatch match;
|
||||
ensure_equals("getLabel() == ''", match.getLabel(), "");
|
||||
|
||||
match.setValues(10, 20, "", "Label", "", "", LLUIColor(), "", "", false,LLUUID::null);
|
||||
match.setValues(10, 20, "", "Label", "", "", LLStyle::Params(), "", "", LLUUID::null);
|
||||
ensure_equals("getLabel() == 'Label'", match.getLabel(), "Label");
|
||||
|
||||
match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
|
||||
match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
|
||||
ensure_equals("getLabel() == '' (2)", match.getLabel(), "");
|
||||
}
|
||||
|
||||
|
|
@ -130,10 +251,10 @@ namespace tut
|
|||
LLUrlMatch match;
|
||||
ensure_equals("getTooltip() == ''", match.getTooltip(), "");
|
||||
|
||||
match.setValues(10, 20, "", "", "Info", "", LLUIColor(), "", "", false,LLUUID::null);
|
||||
match.setValues(10, 20, "", "", "Info", "", LLStyle::Params(), "", "", LLUUID::null);
|
||||
ensure_equals("getTooltip() == 'Info'", match.getTooltip(), "Info");
|
||||
|
||||
match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
|
||||
match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
|
||||
ensure_equals("getTooltip() == '' (2)", match.getTooltip(), "");
|
||||
}
|
||||
|
||||
|
|
@ -146,10 +267,10 @@ namespace tut
|
|||
LLUrlMatch match;
|
||||
ensure_equals("getIcon() == ''", match.getIcon(), "");
|
||||
|
||||
match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "", "", false,LLUUID::null);
|
||||
match.setValues(10, 20, "", "", "", "Icon", LLStyle::Params(), "", "", LLUUID::null);
|
||||
ensure_equals("getIcon() == 'Icon'", match.getIcon(), "Icon");
|
||||
|
||||
match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
|
||||
match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
|
||||
ensure_equals("getIcon() == '' (2)", match.getIcon(), "");
|
||||
}
|
||||
|
||||
|
|
@ -162,10 +283,10 @@ namespace tut
|
|||
LLUrlMatch match;
|
||||
ensure("getMenuName() empty", match.getMenuName().empty());
|
||||
|
||||
match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "xui_file.xml", "", false,LLUUID::null);
|
||||
match.setValues(10, 20, "", "", "", "Icon", LLStyle::Params(), "xui_file.xml", "", LLUUID::null);
|
||||
ensure_equals("getMenuName() == \"xui_file.xml\"", match.getMenuName(), "xui_file.xml");
|
||||
|
||||
match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
|
||||
match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
|
||||
ensure("getMenuName() empty (2)", match.getMenuName().empty());
|
||||
}
|
||||
|
||||
|
|
@ -178,10 +299,10 @@ namespace tut
|
|||
LLUrlMatch match;
|
||||
ensure("getLocation() empty", match.getLocation().empty());
|
||||
|
||||
match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "xui_file.xml", "Paris", false,LLUUID::null);
|
||||
match.setValues(10, 20, "", "", "", "Icon", LLStyle::Params(), "xui_file.xml", "Paris", LLUUID::null);
|
||||
ensure_equals("getLocation() == \"Paris\"", match.getLocation(), "Paris");
|
||||
|
||||
match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null);
|
||||
match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);
|
||||
ensure("getLocation() empty (2)", match.getLocation().empty());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask)
|
|||
std::string filename;
|
||||
std::string fullpath;
|
||||
S32 result;
|
||||
while (getNextFileInDir(dirname, mask, filename, FALSE))
|
||||
while (getNextFileInDir(dirname, mask, filename))
|
||||
{
|
||||
fullpath = dirname;
|
||||
fullpath += getDirDelimiter();
|
||||
|
|
|
|||
|
|
@ -74,8 +74,32 @@ class LLDir
|
|||
|
||||
// pure virtual functions
|
||||
virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask) = 0;
|
||||
virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap) = 0;
|
||||
virtual void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) = 0;
|
||||
|
||||
/// Walk the files in a directory, with file pattern matching
|
||||
virtual BOOL getNextFileInDir(const std::string& dirname, ///< directory path - must end in trailing slash!
|
||||
const std::string& mask, ///< file pattern string (use "*" for all)
|
||||
std::string& fname ///< output: found file name
|
||||
) = 0;
|
||||
/**<
|
||||
* @returns true if a file was found, false if the entire directory has been scanned.
|
||||
*
|
||||
* @note that this function is NOT thread safe
|
||||
*
|
||||
* This function may not be used to scan part of a directory, then start a new search of a different
|
||||
* directory, and then restart the first search where it left off; the entire search must run to
|
||||
* completion or be abandoned - there is no restart.
|
||||
*
|
||||
* @bug: See http://jira.secondlife.com/browse/VWR-23697
|
||||
* and/or the tests in test/lldir_test.cpp
|
||||
* This is known to fail with patterns that have both:
|
||||
* a wildcard left of a . and more than one sequential ? right of a .
|
||||
* the pattern foo.??x appears to work
|
||||
* but *.??x or foo?.??x do not
|
||||
*
|
||||
* @todo this really should be rewritten as an iterator object, and the
|
||||
* filtering should be done in a platform-independent way.
|
||||
*/
|
||||
|
||||
virtual std::string getCurPath() = 0;
|
||||
virtual BOOL fileExists(const std::string &filename) const = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -243,8 +243,7 @@ U32 LLDir_Linux::countFilesInDir(const std::string &dirname, const std::string &
|
|||
}
|
||||
|
||||
// get the next file in the directory
|
||||
// automatically wrap if we've hit the end
|
||||
BOOL LLDir_Linux::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap)
|
||||
BOOL LLDir_Linux::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
|
||||
{
|
||||
glob_t g;
|
||||
BOOL result = FALSE;
|
||||
|
|
@ -276,11 +275,6 @@ BOOL LLDir_Linux::getNextFileInDir(const std::string &dirname, const std::string
|
|||
|
||||
mCurrentDirIndex++;
|
||||
|
||||
if((mCurrentDirIndex >= (int)g.gl_pathc) && wrap)
|
||||
{
|
||||
mCurrentDirIndex = 0;
|
||||
}
|
||||
|
||||
if(mCurrentDirIndex < (int)g.gl_pathc)
|
||||
{
|
||||
// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl;
|
||||
|
|
@ -308,47 +302,7 @@ BOOL LLDir_Linux::getNextFileInDir(const std::string &dirname, const std::string
|
|||
}
|
||||
|
||||
|
||||
// get a random file in the directory
|
||||
// automatically wrap if we've hit the end
|
||||
void LLDir_Linux::getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
|
||||
{
|
||||
S32 num_files;
|
||||
S32 which_file;
|
||||
DIR *dirp;
|
||||
dirent *entryp = NULL;
|
||||
|
||||
fname = "";
|
||||
|
||||
num_files = countFilesInDir(dirname,mask);
|
||||
if (!num_files)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
which_file = ll_rand(num_files);
|
||||
|
||||
// llinfos << "Random select file #" << which_file << llendl;
|
||||
|
||||
// which_file now indicates the (zero-based) index to which file to play
|
||||
|
||||
if (!((dirp = opendir(dirname.c_str()))))
|
||||
{
|
||||
while (which_file--)
|
||||
{
|
||||
if (!((entryp = readdir(dirp))))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!which_file) && entryp)
|
||||
{
|
||||
fname = entryp->d_name;
|
||||
}
|
||||
|
||||
closedir(dirp);
|
||||
}
|
||||
}
|
||||
|
||||
std::string LLDir_Linux::getCurPath()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -43,8 +43,7 @@ public:
|
|||
public:
|
||||
virtual std::string getCurPath();
|
||||
virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask);
|
||||
virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap);
|
||||
virtual void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname);
|
||||
virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname);
|
||||
/*virtual*/ BOOL fileExists(const std::string &filename) const;
|
||||
|
||||
/*virtual*/ std::string getLLPluginLauncher();
|
||||
|
|
|
|||
|
|
@ -259,8 +259,7 @@ U32 LLDir_Mac::countFilesInDir(const std::string &dirname, const std::string &ma
|
|||
}
|
||||
|
||||
// get the next file in the directory
|
||||
// automatically wrap if we've hit the end
|
||||
BOOL LLDir_Mac::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap)
|
||||
BOOL LLDir_Mac::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
|
||||
{
|
||||
glob_t g;
|
||||
BOOL result = FALSE;
|
||||
|
|
@ -292,11 +291,6 @@ BOOL LLDir_Mac::getNextFileInDir(const std::string &dirname, const std::string &
|
|||
|
||||
mCurrentDirIndex++;
|
||||
|
||||
if((mCurrentDirIndex >= g.gl_pathc) && wrap)
|
||||
{
|
||||
mCurrentDirIndex = 0;
|
||||
}
|
||||
|
||||
if(mCurrentDirIndex < g.gl_pathc)
|
||||
{
|
||||
// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl;
|
||||
|
|
@ -323,41 +317,7 @@ BOOL LLDir_Mac::getNextFileInDir(const std::string &dirname, const std::string &
|
|||
return(result);
|
||||
}
|
||||
|
||||
// get a random file in the directory
|
||||
void LLDir_Mac::getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
|
||||
{
|
||||
S32 which_file;
|
||||
glob_t g;
|
||||
fname = "";
|
||||
|
||||
std::string tmp_str;
|
||||
tmp_str = dirname;
|
||||
tmp_str += mask;
|
||||
|
||||
if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0)
|
||||
{
|
||||
if(g.gl_pathc > 0)
|
||||
{
|
||||
|
||||
which_file = ll_rand(g.gl_pathc);
|
||||
|
||||
// llinfos << "getRandomFileInDir: returning number " << which_file << ", path is " << g.gl_pathv[which_file] << llendl;
|
||||
// The API wants just the filename, not the full path.
|
||||
//fname = g.gl_pathv[which_file];
|
||||
|
||||
char *s = strrchr(g.gl_pathv[which_file], '/');
|
||||
|
||||
if(s == NULL)
|
||||
s = g.gl_pathv[which_file];
|
||||
else if(s[0] == '/')
|
||||
s++;
|
||||
|
||||
fname = s;
|
||||
}
|
||||
|
||||
globfree(&g);
|
||||
}
|
||||
}
|
||||
|
||||
S32 LLDir_Mac::deleteFilesInDir(const std::string &dirname, const std::string &mask)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -43,8 +43,7 @@ public:
|
|||
virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask);
|
||||
virtual std::string getCurPath();
|
||||
virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask);
|
||||
virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap);
|
||||
virtual void getRandomFileInDir(const std::string &dirname, const std::string &ask, std::string &fname);
|
||||
virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname);
|
||||
virtual BOOL fileExists(const std::string &filename) const;
|
||||
|
||||
/*virtual*/ std::string getLLPluginLauncher();
|
||||
|
|
|
|||
|
|
@ -261,8 +261,7 @@ U32 LLDir_Solaris::countFilesInDir(const std::string &dirname, const std::string
|
|||
}
|
||||
|
||||
// get the next file in the directory
|
||||
// automatically wrap if we've hit the end
|
||||
BOOL LLDir_Solaris::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap)
|
||||
BOOL LLDir_Solaris::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
|
||||
{
|
||||
glob_t g;
|
||||
BOOL result = FALSE;
|
||||
|
|
@ -294,11 +293,6 @@ BOOL LLDir_Solaris::getNextFileInDir(const std::string &dirname, const std::stri
|
|||
|
||||
mCurrentDirIndex++;
|
||||
|
||||
if((mCurrentDirIndex >= (int)g.gl_pathc) && wrap)
|
||||
{
|
||||
mCurrentDirIndex = 0;
|
||||
}
|
||||
|
||||
if(mCurrentDirIndex < (int)g.gl_pathc)
|
||||
{
|
||||
// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl;
|
||||
|
|
@ -326,47 +320,7 @@ BOOL LLDir_Solaris::getNextFileInDir(const std::string &dirname, const std::stri
|
|||
}
|
||||
|
||||
|
||||
// get a random file in the directory
|
||||
// automatically wrap if we've hit the end
|
||||
void LLDir_Solaris::getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
|
||||
{
|
||||
S32 num_files;
|
||||
S32 which_file;
|
||||
DIR *dirp;
|
||||
dirent *entryp = NULL;
|
||||
|
||||
fname = "";
|
||||
|
||||
num_files = countFilesInDir(dirname,mask);
|
||||
if (!num_files)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
which_file = ll_rand(num_files);
|
||||
|
||||
// llinfos << "Random select file #" << which_file << llendl;
|
||||
|
||||
// which_file now indicates the (zero-based) index to which file to play
|
||||
|
||||
if (!((dirp = opendir(dirname.c_str()))))
|
||||
{
|
||||
while (which_file--)
|
||||
{
|
||||
if (!((entryp = readdir(dirp))))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!which_file) && entryp)
|
||||
{
|
||||
fname = entryp->d_name;
|
||||
}
|
||||
|
||||
closedir(dirp);
|
||||
}
|
||||
}
|
||||
|
||||
std::string LLDir_Solaris::getCurPath()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -43,8 +43,7 @@ public:
|
|||
public:
|
||||
virtual std::string getCurPath();
|
||||
virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask);
|
||||
virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap);
|
||||
virtual void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname);
|
||||
virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname);
|
||||
/*virtual*/ BOOL fileExists(const std::string &filename) const;
|
||||
|
||||
private:
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue