summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/contributions.txt10
-rw-r--r--indra/cmake/Boost.cmake18
-rw-r--r--indra/cmake/GetPrerequisites_2_8.cmake1572
-rw-r--r--indra/cmake/LLAddBuildTest.cmake552
-rw-r--r--indra/integration_tests/llui_libtest/llui_libtest.cpp5
-rw-r--r--indra/linux_updater/linux_updater.cpp15
-rw-r--r--indra/llcommon/llfile.cpp11
-rw-r--r--indra/llcommon/llfile.h2
-rw-r--r--indra/llmath/llbbox.cpp22
-rw-r--r--indra/llmath/llbbox.h4
-rw-r--r--indra/llmessage/llregionflags.h18
-rw-r--r--indra/llui/llfloater.cpp5
-rw-r--r--indra/llui/llmenugl.cpp4
-rw-r--r--indra/llui/llurlentry.cpp87
-rw-r--r--indra/llui/llurlentry.h39
-rw-r--r--indra/llui/tests/llurlentry_stub.cpp18
-rw-r--r--indra/llvfs/CMakeLists.txt7
-rw-r--r--indra/llvfs/lldir.cpp6
-rw-r--r--indra/llvfs/lldir.h25
-rw-r--r--indra/llvfs/lldir_linux.cpp62
-rw-r--r--indra/llvfs/lldir_linux.h1
-rw-r--r--indra/llvfs/lldir_mac.cpp61
-rw-r--r--indra/llvfs/lldir_mac.h1
-rw-r--r--indra/llvfs/lldir_solaris.cpp62
-rw-r--r--indra/llvfs/lldir_solaris.h1
-rw-r--r--indra/llvfs/lldir_win32.cpp61
-rw-r--r--indra/llvfs/lldir_win32.h3
-rw-r--r--indra/llvfs/lldiriterator.cpp203
-rw-r--r--indra/llvfs/lldiriterator.h87
-rw-r--r--indra/llvfs/tests/lldir_test.cpp38
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/llagent.cpp5
-rw-r--r--indra/newview/llappearancemgr.cpp12
-rw-r--r--indra/newview/llappviewer.cpp24
-rw-r--r--indra/newview/llappviewerlinux.cpp5
-rw-r--r--indra/newview/llassetuploadresponders.cpp1
-rw-r--r--indra/newview/llfloateruipreview.cpp26
-rw-r--r--indra/newview/llfloaterwebcontent.cpp804
-rw-r--r--indra/newview/llfloaterwebcontent.h162
-rw-r--r--indra/newview/llimview.cpp26
-rw-r--r--indra/newview/llimview.h2
-rw-r--r--indra/newview/llinventoryfunctions.cpp6
-rw-r--r--indra/newview/lllocationinputctrl.cpp4
-rw-r--r--indra/newview/lllogchat.cpp22
-rw-r--r--indra/newview/llpanelme.cpp24
-rw-r--r--indra/newview/llremoteparcelrequest.cpp13
-rw-r--r--indra/newview/llsidetray.cpp4
-rw-r--r--indra/newview/llspatialpartition.cpp48
-rw-r--r--indra/newview/llstartup.cpp9
-rw-r--r--indra/newview/llviewermedia.cpp4
-rw-r--r--indra/newview/llviewermenu.cpp12
-rw-r--r--indra/newview/llviewerobject.cpp51
-rw-r--r--indra/newview/llviewerobject.h17
-rw-r--r--indra/newview/llviewerobjectlist.cpp92
-rw-r--r--indra/newview/llviewerparceloverlay.cpp29
-rw-r--r--indra/newview/llviewerparceloverlay.h7
-rw-r--r--indra/newview/llviewerregion.cpp70
-rw-r--r--indra/newview/llviewerregion.h24
-rw-r--r--indra/newview/llviewerstatsrecorder.cpp258
-rw-r--r--indra/newview/llviewerstatsrecorder.h97
-rw-r--r--indra/newview/llvoavatar.cpp25
-rw-r--r--indra/newview/llvocache.cpp202
-rw-r--r--indra/newview/llvocache.h13
-rw-r--r--indra/newview/llwaterparammanager.cpp11
-rw-r--r--indra/newview/llwlparammanager.cpp11
-rw-r--r--indra/newview/pipeline.h1
-rw-r--r--indra/newview/skins/default/colors.xml6
-rw-r--r--indra/newview/skins/default/xui/da/notifications.xml2
-rw-r--r--indra/newview/skins/default/xui/de/notifications.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_web_content.xml380
-rw-r--r--indra/newview/skins/default/xui/en/menu_object.xml20
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml22
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_group_land_money.xml10
-rw-r--r--indra/newview/skins/default/xui/en/widgets/floater.xml1
-rw-r--r--indra/newview/skins/default/xui/es/notifications.xml2
-rw-r--r--indra/newview/skins/default/xui/fr/notifications.xml2
-rw-r--r--indra/newview/skins/default/xui/it/notifications.xml2
-rw-r--r--indra/newview/skins/default/xui/ja/notifications.xml2
-rw-r--r--indra/newview/skins/default/xui/pl/notifications.xml2
-rw-r--r--indra/newview/skins/default/xui/pt/notifications.xml4
-rw-r--r--indra/newview/tests/llremoteparcelrequest_test.cpp270
-rw-r--r--indra/viewer_components/updater/tests/llupdaterservice_test.cpp394
83 files changed, 3583 insertions, 2663 deletions
diff --git a/doc/contributions.txt b/doc/contributions.txt
index 3b14ce5125..f21354b406 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -219,6 +219,8 @@ Catherine Pfeffer
Celierra Darling
VWR-1274
VWR-6975
+Coaldust Numbers
+ VWR-1095
Cron Stardust
VWR-10579
Cypren Christenson
@@ -364,15 +366,17 @@ JB Kraft
Joghert LeSabre
VWR-64
Jonathan Yap
- STORM-596
STORM-523
+ STORM-596
+ STORM-615
STORM-616
STORM-679
- STORM-737
+ STORM-723
STORM-726
+ STORM-737
+ STORM-785
STORM-812
VWR-17801
- STORM-785
Kage Pixel
VWR-11
Ken March
diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake
index 7ce57a5572..012d3c2ab2 100644
--- a/indra/cmake/Boost.cmake
+++ b/indra/cmake/Boost.cmake
@@ -10,6 +10,8 @@ if (STANDALONE)
set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-mt)
set(BOOST_REGEX_LIBRARY boost_regex-mt)
set(BOOST_SIGNALS_LIBRARY boost_signals-mt)
+ set(BOOST_SYSTEM_LIBRARY boost_system-mt)
+ set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-mt)
else (STANDALONE)
use_prebuilt_binary(boost)
set(Boost_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
@@ -26,6 +28,12 @@ else (STANDALONE)
set(BOOST_SIGNALS_LIBRARY
optimized libboost_signals-vc71-mt-s-${BOOST_VERSION}
debug libboost_signals-vc71-mt-sgd-${BOOST_VERSION})
+ set(BOOST_SYSTEM_LIBRARY
+ optimized libboost_system-vc71-mt-s-${BOOST_VERSION}
+ debug libboost_system-vc71-mt-sgd-${BOOST_VERSION})
+ set(BOOST_FILESYSTEM_LIBRARY
+ optimized libboost_filesystem-vc71-mt-s-${BOOST_VERSION}
+ debug libboost_filesystem-vc71-mt-sgd-${BOOST_VERSION})
else (MSVC71)
set(BOOST_PROGRAM_OPTIONS_LIBRARY
optimized libboost_program_options-vc80-mt-${BOOST_VERSION}
@@ -36,14 +44,24 @@ else (STANDALONE)
set(BOOST_SIGNALS_LIBRARY
optimized libboost_signals-vc80-mt-${BOOST_VERSION}
debug libboost_signals-vc80-mt-gd-${BOOST_VERSION})
+ set(BOOST_SYSTEM_LIBRARY
+ optimized libboost_system-vc80-mt-${BOOST_VERSION}
+ debug libboost_system-vc80-mt-gd-${BOOST_VERSION})
+ set(BOOST_FILESYSTEM_LIBRARY
+ optimized libboost_filesystem-vc80-mt-${BOOST_VERSION}
+ debug libboost_filesystem-vc80-mt-gd-${BOOST_VERSION})
endif (MSVC71)
elseif (DARWIN)
set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-xgcc40-mt)
set(BOOST_REGEX_LIBRARY boost_regex-xgcc40-mt)
set(BOOST_SIGNALS_LIBRARY boost_signals-xgcc40-mt)
+ set(BOOST_SYSTEM_LIBRARY boost_system-xgcc40-mt)
+ set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-xgcc40-mt)
elseif (LINUX)
set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-gcc41-mt)
set(BOOST_REGEX_LIBRARY boost_regex-gcc41-mt)
set(BOOST_SIGNALS_LIBRARY boost_signals-gcc41-mt)
+ set(BOOST_SYSTEM_LIBRARY boost_system-gcc41-mt)
+ set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-gcc41-mt)
endif (WINDOWS)
endif (STANDALONE)
diff --git a/indra/cmake/GetPrerequisites_2_8.cmake b/indra/cmake/GetPrerequisites_2_8.cmake
index 5a24842c89..05ec1539ba 100644
--- a/indra/cmake/GetPrerequisites_2_8.cmake
+++ b/indra/cmake/GetPrerequisites_2_8.cmake
@@ -1,786 +1,786 @@
-# GetPrerequisites.cmake
-#
-# This script provides functions to list the .dll, .dylib or .so files that an
-# executable or shared library file depends on. (Its prerequisites.)
-#
-# It uses various tools to obtain the list of required shared library files:
-# dumpbin (Windows)
-# ldd (Linux/Unix)
-# otool (Mac OSX)
-#
-# The following functions are provided by this script:
-# gp_append_unique
-# is_file_executable
-# gp_item_default_embedded_path
-# (projects can override with gp_item_default_embedded_path_override)
-# gp_resolve_item
-# (projects can override with gp_resolve_item_override)
-# gp_resolved_file_type
-# gp_file_type
-# get_prerequisites
-# list_prerequisites
-# list_prerequisites_by_glob
-#
-# Requires CMake 2.6 or greater because it uses function, break, return and
-# PARENT_SCOPE.
-
-#=============================================================================
-# Copyright 2008-2009 Kitware, Inc.
-#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
-# (To distributed this file outside of CMake, substitute the full
-# License text for the above reference.)
-
-# gp_append_unique list_var value
-#
-# Append value to the list variable ${list_var} only if the value is not
-# already in the list.
-#
-function(gp_append_unique list_var value)
- set(contains 0)
-
- foreach(item ${${list_var}})
- if("${item}" STREQUAL "${value}")
- set(contains 1)
- break()
- endif("${item}" STREQUAL "${value}")
- endforeach(item)
-
- if(NOT contains)
- set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE)
- endif(NOT contains)
-endfunction(gp_append_unique)
-
-
-# is_file_executable file result_var
-#
-# Return 1 in ${result_var} if ${file} is a binary executable.
-#
-# Return 0 in ${result_var} otherwise.
-#
-function(is_file_executable file result_var)
- #
- # A file is not executable until proven otherwise:
- #
- set(${result_var} 0 PARENT_SCOPE)
-
- get_filename_component(file_full "${file}" ABSOLUTE)
- string(TOLOWER "${file_full}" file_full_lower)
-
- # If file name ends in .exe on Windows, *assume* executable:
- #
- if(WIN32)
- if("${file_full_lower}" MATCHES "\\.exe$")
- set(${result_var} 1 PARENT_SCOPE)
- return()
- endif("${file_full_lower}" MATCHES "\\.exe$")
-
- # A clause could be added here that uses output or return value of dumpbin
- # to determine ${result_var}. In 99%+? practical cases, the exe name
- # match will be sufficient...
- #
- endif(WIN32)
-
- # Use the information returned from the Unix shell command "file" to
- # determine if ${file_full} should be considered an executable file...
- #
- # If the file command's output contains "executable" and does *not* contain
- # "text" then it is likely an executable suitable for prerequisite analysis
- # via the get_prerequisites macro.
- #
- if(UNIX)
- if(NOT file_cmd)
- find_program(file_cmd "file")
- endif(NOT file_cmd)
-
- if(file_cmd)
- execute_process(COMMAND "${file_cmd}" "${file_full}"
- OUTPUT_VARIABLE file_ov
- OUTPUT_STRIP_TRAILING_WHITESPACE
- )
-
- # Replace the name of the file in the output with a placeholder token
- # (the string " _file_full_ ") so that just in case the path name of
- # the file contains the word "text" or "executable" we are not fooled
- # into thinking "the wrong thing" because the file name matches the
- # other 'file' command output we are looking for...
- #
- string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}")
- string(TOLOWER "${file_ov}" file_ov)
-
- #message(STATUS "file_ov='${file_ov}'")
- if("${file_ov}" MATCHES "executable")
- #message(STATUS "executable!")
- if("${file_ov}" MATCHES "text")
- #message(STATUS "but text, so *not* a binary executable!")
- else("${file_ov}" MATCHES "text")
- set(${result_var} 1 PARENT_SCOPE)
- return()
- endif("${file_ov}" MATCHES "text")
- endif("${file_ov}" MATCHES "executable")
- else(file_cmd)
- message(STATUS "warning: No 'file' command, skipping execute_process...")
- endif(file_cmd)
- endif(UNIX)
-endfunction(is_file_executable)
-
-
-# gp_item_default_embedded_path item default_embedded_path_var
-#
-# Return the path that others should refer to the item by when the item
-# is embedded inside a bundle.
-#
-# Override on a per-project basis by providing a project-specific
-# gp_item_default_embedded_path_override function.
-#
-function(gp_item_default_embedded_path item default_embedded_path_var)
-
- # On Windows and Linux, "embed" prerequisites in the same directory
- # as the executable by default:
- #
- set(path "@executable_path")
- set(overridden 0)
-
- # On the Mac, relative to the executable depending on the type
- # of the thing we are embedding:
- #
- if(APPLE)
- #
- # The assumption here is that all executables in the bundle will be
- # in same-level-directories inside the bundle. The parent directory
- # of an executable inside the bundle should be MacOS or a sibling of
- # MacOS and all embedded paths returned from here will begin with
- # "@executable_path/../" and will work from all executables in all
- # such same-level-directories inside the bundle.
- #
-
- # By default, embed things right next to the main bundle executable:
- #
- set(path "@executable_path/../../Contents/MacOS")
-
- # Embed .dylibs right next to the main bundle executable:
- #
- if(item MATCHES "\\.dylib$")
- set(path "@executable_path/../MacOS")
- set(overridden 1)
- endif(item MATCHES "\\.dylib$")
-
- # Embed frameworks in the embedded "Frameworks" directory (sibling of MacOS):
- #
- if(NOT overridden)
- if(item MATCHES "[^/]+\\.framework/")
- set(path "@executable_path/../Frameworks")
- set(overridden 1)
- endif(item MATCHES "[^/]+\\.framework/")
- endif(NOT overridden)
- endif()
-
- # Provide a hook so that projects can override the default embedded location
- # of any given library by whatever logic they choose:
- #
- if(COMMAND gp_item_default_embedded_path_override)
- gp_item_default_embedded_path_override("${item}" path)
- endif(COMMAND gp_item_default_embedded_path_override)
-
- set(${default_embedded_path_var} "${path}" PARENT_SCOPE)
-endfunction(gp_item_default_embedded_path)
-
-
-# gp_resolve_item context item exepath dirs resolved_item_var
-#
-# Resolve an item into an existing full path file.
-#
-# Override on a per-project basis by providing a project-specific
-# gp_resolve_item_override function.
-#
-function(gp_resolve_item context item exepath dirs resolved_item_var)
- set(resolved 0)
- set(resolved_item "${item}")
-
- # Is it already resolved?
- #
- if(EXISTS "${resolved_item}")
- set(resolved 1)
- endif(EXISTS "${resolved_item}")
-
- if(NOT resolved)
- if(item MATCHES "@executable_path")
- #
- # @executable_path references are assumed relative to exepath
- #
- string(REPLACE "@executable_path" "${exepath}" ri "${item}")
- get_filename_component(ri "${ri}" ABSOLUTE)
-
- if(EXISTS "${ri}")
- #message(STATUS "info: embedded item exists (${ri})")
- set(resolved 1)
- set(resolved_item "${ri}")
- else(EXISTS "${ri}")
- message(STATUS "warning: embedded item does not exist '${ri}'")
- endif(EXISTS "${ri}")
- endif(item MATCHES "@executable_path")
- endif(NOT resolved)
-
- if(NOT resolved)
- if(item MATCHES "@loader_path")
- #
- # @loader_path references are assumed relative to the
- # PATH of the given "context" (presumably another library)
- #
- get_filename_component(contextpath "${context}" PATH)
- string(REPLACE "@loader_path" "${contextpath}" ri "${item}")
- get_filename_component(ri "${ri}" ABSOLUTE)
-
- if(EXISTS "${ri}")
- #message(STATUS "info: embedded item exists (${ri})")
- set(resolved 1)
- set(resolved_item "${ri}")
- else(EXISTS "${ri}")
- message(STATUS "warning: embedded item does not exist '${ri}'")
- endif(EXISTS "${ri}")
- endif(item MATCHES "@loader_path")
- endif(NOT resolved)
-
- if(NOT resolved)
- set(ri "ri-NOTFOUND")
- find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH)
- find_file(ri "${item}" ${exepath} ${dirs} /usr/lib)
- if(ri)
- #message(STATUS "info: 'find_file' in exepath/dirs (${ri})")
- set(resolved 1)
- set(resolved_item "${ri}")
- set(ri "ri-NOTFOUND")
- endif(ri)
- endif(NOT resolved)
-
- if(NOT resolved)
- if(item MATCHES "[^/]+\\.framework/")
- set(fw "fw-NOTFOUND")
- find_file(fw "${item}"
- "~/Library/Frameworks"
- "/Library/Frameworks"
- "/System/Library/Frameworks"
- )
- if(fw)
- #message(STATUS "info: 'find_file' found framework (${fw})")
- set(resolved 1)
- set(resolved_item "${fw}")
- set(fw "fw-NOTFOUND")
- endif(fw)
- endif(item MATCHES "[^/]+\\.framework/")
- endif(NOT resolved)
-
- # Using find_program on Windows will find dll files that are in the PATH.
- # (Converting simple file names into full path names if found.)
- #
- if(WIN32)
- if(NOT resolved)
- set(ri "ri-NOTFOUND")
- find_program(ri "${item}" PATHS "${exepath};${dirs}" NO_DEFAULT_PATH)
- find_program(ri "${item}" PATHS "${exepath};${dirs}")
- if(ri)
- #message(STATUS "info: 'find_program' in exepath/dirs (${ri})")
- set(resolved 1)
- set(resolved_item "${ri}")
- set(ri "ri-NOTFOUND")
- endif(ri)
- endif(NOT resolved)
- endif(WIN32)
-
- # Provide a hook so that projects can override item resolution
- # by whatever logic they choose:
- #
- if(COMMAND gp_resolve_item_override)
- gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved)
- endif(COMMAND gp_resolve_item_override)
-
- if(NOT resolved)
- message(STATUS "
-warning: cannot resolve item '${item}'
-
- possible problems:
- need more directories?
- need to use InstallRequiredSystemLibraries?
- run in install tree instead of build tree?
-")
-# message(STATUS "
-#******************************************************************************
-#warning: cannot resolve item '${item}'
-#
-# possible problems:
-# need more directories?
-# need to use InstallRequiredSystemLibraries?
-# run in install tree instead of build tree?
-#
-# context='${context}'
-# item='${item}'
-# exepath='${exepath}'
-# dirs='${dirs}'
-# resolved_item_var='${resolved_item_var}'
-#******************************************************************************
-#")
- endif(NOT resolved)
-
- set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE)
-endfunction(gp_resolve_item)
-
-
-# gp_resolved_file_type original_file file exepath dirs type_var
-#
-# Return the type of ${file} with respect to ${original_file}. String
-# describing type of prerequisite is returned in variable named ${type_var}.
-#
-# Use ${exepath} and ${dirs} if necessary to resolve non-absolute ${file}
-# values -- but only for non-embedded items.
-#
-# Possible types are:
-# system
-# local
-# embedded
-# other
-#
-function(gp_resolved_file_type original_file file exepath dirs type_var)
- #message(STATUS "**")
-
- if(NOT IS_ABSOLUTE "${original_file}")
- message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file")
- endif()
-
- set(is_embedded 0)
- set(is_local 0)
- set(is_system 0)
-
- set(resolved_file "${file}")
-
- if("${file}" MATCHES "^@(executable|loader)_path")
- set(is_embedded 1)
- endif()
-
- if(NOT is_embedded)
- if(NOT IS_ABSOLUTE "${file}")
- gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file)
- endif()
-
- string(TOLOWER "${original_file}" original_lower)
- string(TOLOWER "${resolved_file}" lower)
-
- if(UNIX)
- if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11R6/)")
- set(is_system 1)
- endif()
- endif()
-
- if(APPLE)
- if(resolved_file MATCHES "^(/System/Library/|/usr/lib/)")
- set(is_system 1)
- endif()
- endif()
-
- if(WIN32)
- string(TOLOWER "$ENV{SystemRoot}" sysroot)
- string(REGEX REPLACE "\\\\" "/" sysroot "${sysroot}")
-
- string(TOLOWER "$ENV{windir}" windir)
- string(REGEX REPLACE "\\\\" "/" windir "${windir}")
-
- if(lower MATCHES "^(${sysroot}/system|${windir}/system|${sysroot}/syswow|${windir}/syswow|(.*/)*msvc[^/]+dll)")
- set(is_system 1)
- endif()
- endif()
-
- if(NOT is_system)
- get_filename_component(original_path "${original_lower}" PATH)
- get_filename_component(path "${lower}" PATH)
- if("${original_path}" STREQUAL "${path}")
- set(is_local 1)
- endif()
- endif()
- endif()
-
- # Return type string based on computed booleans:
- #
- set(type "other")
-
- if(is_system)
- set(type "system")
- elseif(is_embedded)
- set(type "embedded")
- elseif(is_local)
- set(type "local")
- endif()
-
- #message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'")
- #message(STATUS " type: '${type}'")
-
- if(NOT is_embedded)
- if(NOT IS_ABSOLUTE "${resolved_file}")
- if(lower MATCHES "^msvc[^/]+dll" AND is_system)
- message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'")
- else()
- message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect")
- endif()
- endif()
- endif()
-
- set(${type_var} "${type}" PARENT_SCOPE)
-
- #message(STATUS "**")
-endfunction()
-
-
-# gp_file_type original_file file type_var
-#
-# Return the type of ${file} with respect to ${original_file}. String
-# describing type of prerequisite is returned in variable named ${type_var}.
-#
-# Possible types are:
-# system
-# local
-# embedded
-# other
-#
-function(gp_file_type original_file file type_var)
- if(NOT IS_ABSOLUTE "${original_file}")
- message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file")
- endif()
-
- get_filename_component(exepath "${original_file}" PATH)
-
- set(type "")
- gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type)
-
- set(${type_var} "${type}" PARENT_SCOPE)
-endfunction(gp_file_type)
-
-
-# get_prerequisites target prerequisites_var exclude_system recurse dirs
-#
-# Get the list of shared library files required by ${target}. The list in
-# the variable named ${prerequisites_var} should be empty on first entry to
-# this function. On exit, ${prerequisites_var} will contain the list of
-# required shared library files.
-#
-# target is the full path to an executable file
-#
-# prerequisites_var is the name of a CMake variable to contain the results
-#
-# exclude_system is 0 or 1: 0 to include "system" prerequisites , 1 to
-# exclude them
-#
-# recurse is 0 or 1: 0 for direct prerequisites only, 1 for all prerequisites
-# recursively
-#
-# exepath is the path to the top level executable used for @executable_path
-# replacment on the Mac
-#
-# dirs is a list of paths where libraries might be found: these paths are
-# searched first when a target without any path info is given. Then standard
-# system locations are also searched: PATH, Framework locations, /usr/lib...
-#
-function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs)
- set(verbose 0)
- set(eol_char "E")
-
- if(NOT IS_ABSOLUTE "${target}")
- message("warning: target '${target}' is not absolute...")
- endif(NOT IS_ABSOLUTE "${target}")
-
- if(NOT EXISTS "${target}")
- message("warning: target '${target}' does not exist...")
- endif(NOT EXISTS "${target}")
-
- # <setup-gp_tool-vars>
- #
- # Try to choose the right tool by default. Caller can set gp_tool prior to
- # calling this function to force using a different tool.
- #
- if("${gp_tool}" STREQUAL "")
- set(gp_tool "ldd")
- if(APPLE)
- set(gp_tool "otool")
- endif(APPLE)
- if(WIN32)
- set(gp_tool "dumpbin")
- endif(WIN32)
- endif("${gp_tool}" STREQUAL "")
-
- set(gp_tool_known 0)
-
- if("${gp_tool}" STREQUAL "ldd")
- set(gp_cmd_args "")
- set(gp_regex "^[\t ]*[^\t ]+ => ([^\t ]+).*${eol_char}$")
- set(gp_regex_cmp_count 1)
- set(gp_tool_known 1)
- endif("${gp_tool}" STREQUAL "ldd")
-
- if("${gp_tool}" STREQUAL "otool")
- set(gp_cmd_args "-L")
- set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$")
- set(gp_regex_cmp_count 3)
- set(gp_tool_known 1)
- endif("${gp_tool}" STREQUAL "otool")
-
- if("${gp_tool}" STREQUAL "dumpbin")
- set(gp_cmd_args "/dependents")
- set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$")
- set(gp_regex_cmp_count 1)
- set(gp_tool_known 1)
- set(ENV{VS_UNICODE_OUTPUT} "") # Block extra output from inside VS IDE.
- endif("${gp_tool}" STREQUAL "dumpbin")
-
- if(NOT gp_tool_known)
- message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...")
- message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'")
- message(STATUS "Valid gp_tool values are dumpbin, ldd and otool.")
- return()
- endif(NOT gp_tool_known)
-
- set(gp_cmd_paths ${gp_cmd_paths}
- "C:/Program Files/Microsoft Visual Studio 9.0/VC/bin"
- "C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin"
- "C:/Program Files/Microsoft Visual Studio 8/VC/BIN"
- "C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN"
- "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN"
- "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN"
- "/usr/local/bin"
- "/usr/bin"
- )
-
- find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths})
-
- if(NOT gp_cmd)
- message(STATUS "warning: could not find '${gp_tool}' - cannot analyze prerequisites...")
- return()
- endif(NOT gp_cmd)
-
- if("${gp_tool}" STREQUAL "dumpbin")
- # When running dumpbin, it also needs the "Common7/IDE" directory in the
- # PATH. It will already be in the PATH if being run from a Visual Studio
- # command prompt. Add it to the PATH here in case we are running from a
- # different command prompt.
- #
- get_filename_component(gp_cmd_dir "${gp_cmd}" PATH)
- get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE)
- if(EXISTS "${gp_cmd_dlls_dir}")
- # only add to the path if it is not already in the path
- if(NOT "$ENV{PATH}" MATCHES "${gp_cmd_dlls_dir}")
- set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}")
- endif(NOT "$ENV{PATH}" MATCHES "${gp_cmd_dlls_dir}")
- endif(EXISTS "${gp_cmd_dlls_dir}")
- endif("${gp_tool}" STREQUAL "dumpbin")
- #
- # </setup-gp_tool-vars>
-
- if("${gp_tool}" STREQUAL "ldd")
- set(old_ld_env "$ENV{LD_LIBRARY_PATH}")
- foreach(dir ${exepath} ${dirs})
- set(ENV{LD_LIBRARY_PATH} "${dir}:$ENV{LD_LIBRARY_PATH}")
- endforeach(dir)
- endif("${gp_tool}" STREQUAL "ldd")
-
-
- # Track new prerequisites at each new level of recursion. Start with an
- # empty list at each level:
- #
- set(unseen_prereqs)
-
- # Run gp_cmd on the target:
- #
- execute_process(
- COMMAND ${gp_cmd} ${gp_cmd_args} ${target}
- OUTPUT_VARIABLE gp_cmd_ov
- )
-
- if("${gp_tool}" STREQUAL "ldd")
- set(ENV{LD_LIBRARY_PATH} "${old_ld_env}")
- endif("${gp_tool}" STREQUAL "ldd")
-
- if(verbose)
- message(STATUS "<RawOutput cmd='${gp_cmd} ${gp_cmd_args} ${target}'>")
- message(STATUS "gp_cmd_ov='${gp_cmd_ov}'")
- message(STATUS "</RawOutput>")
- endif(verbose)
-
- get_filename_component(target_dir "${target}" PATH)
-
- # Convert to a list of lines:
- #
- string(REGEX REPLACE ";" "\\\\;" candidates "${gp_cmd_ov}")
- string(REGEX REPLACE "\n" "${eol_char};" candidates "${candidates}")
-
- # Analyze each line for file names that match the regular expression:
- #
- foreach(candidate ${candidates})
- if("${candidate}" MATCHES "${gp_regex}")
- # Extract information from each candidate:
- string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}")
-
- if(gp_regex_cmp_count GREATER 1)
- string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}")
- string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}")
- string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}")
- string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}")
- endif(gp_regex_cmp_count GREATER 1)
-
- if(gp_regex_cmp_count GREATER 2)
- string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}")
- string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}")
- string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}")
- string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}")
- endif(gp_regex_cmp_count GREATER 2)
-
- # Use the raw_item as the list entries returned by this function. Use the
- # gp_resolve_item function to resolve it to an actual full path file if
- # necessary.
- #
- set(item "${raw_item}")
-
- # Add each item unless it is excluded:
- #
- set(add_item 1)
-
- if(${exclude_system})
- set(type "")
- gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type)
- if("${type}" STREQUAL "system")
- set(add_item 0)
- endif("${type}" STREQUAL "system")
- endif(${exclude_system})
-
- if(add_item)
- list(LENGTH ${prerequisites_var} list_length_before_append)
- gp_append_unique(${prerequisites_var} "${item}")
- list(LENGTH ${prerequisites_var} list_length_after_append)
-
- if(${recurse})
- # If item was really added, this is the first time we have seen it.
- # Add it to unseen_prereqs so that we can recursively add *its*
- # prerequisites...
- #
- # But first: resolve its name to an absolute full path name such
- # that the analysis tools can simply accept it as input.
- #
- if(NOT list_length_before_append EQUAL list_length_after_append)
- gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item)
- set(unseen_prereqs ${unseen_prereqs} "${resolved_item}")
- endif(NOT list_length_before_append EQUAL list_length_after_append)
- endif(${recurse})
- endif(add_item)
- else("${candidate}" MATCHES "${gp_regex}")
- if(verbose)
- message(STATUS "ignoring non-matching line: '${candidate}'")
- endif(verbose)
- endif("${candidate}" MATCHES "${gp_regex}")
- endforeach(candidate)
-
- list(LENGTH ${prerequisites_var} prerequisites_var_length)
- if(prerequisites_var_length GREATER 0)
- list(SORT ${prerequisites_var})
- endif(prerequisites_var_length GREATER 0)
- if(${recurse})
- set(more_inputs ${unseen_prereqs})
- foreach(input ${more_inputs})
- get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}")
- endforeach(input)
- endif(${recurse})
-
- set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE)
-endfunction(get_prerequisites)
-
-
-# list_prerequisites target all exclude_system verbose
-#
-# ARGV0 (target) is the full path to an executable file
-#
-# optional ARGV1 (all) is 0 or 1: 0 for direct prerequisites only,
-# 1 for all prerequisites recursively
-#
-# optional ARGV2 (exclude_system) is 0 or 1: 0 to include "system"
-# prerequisites , 1 to exclude them
-#
-# optional ARGV3 (verbose) is 0 or 1: 0 to print only full path
-# names of prerequisites, 1 to print extra information
-#
-function(list_prerequisites target)
- if("${ARGV1}" STREQUAL "")
- set(all 1)
- else("${ARGV1}" STREQUAL "")
- set(all "${ARGV1}")
- endif("${ARGV1}" STREQUAL "")
-
- if("${ARGV2}" STREQUAL "")
- set(exclude_system 0)
- else("${ARGV2}" STREQUAL "")
- set(exclude_system "${ARGV2}")
- endif("${ARGV2}" STREQUAL "")
-
- if("${ARGV3}" STREQUAL "")
- set(verbose 0)
- else("${ARGV3}" STREQUAL "")
- set(verbose "${ARGV3}")
- endif("${ARGV3}" STREQUAL "")
-
- set(count 0)
- set(count_str "")
- set(print_count "${verbose}")
- set(print_prerequisite_type "${verbose}")
- set(print_target "${verbose}")
- set(type_str "")
-
- get_filename_component(exepath "${target}" PATH)
-
- set(prereqs "")
- get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "")
-
- if(print_target)
- message(STATUS "File '${target}' depends on:")
- endif(print_target)
-
- foreach(d ${prereqs})
- math(EXPR count "${count} + 1")
-
- if(print_count)
- set(count_str "${count}. ")
- endif(print_count)
-
- if(print_prerequisite_type)
- gp_file_type("${target}" "${d}" type)
- set(type_str " (${type})")
- endif(print_prerequisite_type)
-
- message(STATUS "${count_str}${d}${type_str}")
- endforeach(d)
-endfunction(list_prerequisites)
-
-
-# list_prerequisites_by_glob glob_arg glob_exp
-#
-# glob_arg is GLOB or GLOB_RECURSE
-#
-# glob_exp is a globbing expression used with "file(GLOB" to retrieve a list
-# of matching files. If a matching file is executable, its prerequisites are
-# listed.
-#
-# Any additional (optional) arguments provided are passed along as the
-# optional arguments to the list_prerequisites calls.
-#
-function(list_prerequisites_by_glob glob_arg glob_exp)
- message(STATUS "=============================================================================")
- message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'")
- message(STATUS "")
- file(${glob_arg} file_list ${glob_exp})
- foreach(f ${file_list})
- is_file_executable("${f}" is_f_executable)
- if(is_f_executable)
- message(STATUS "=============================================================================")
- list_prerequisites("${f}" ${ARGN})
- message(STATUS "")
- endif(is_f_executable)
- endforeach(f)
-endfunction(list_prerequisites_by_glob)
+# GetPrerequisites.cmake
+#
+# This script provides functions to list the .dll, .dylib or .so files that an
+# executable or shared library file depends on. (Its prerequisites.)
+#
+# It uses various tools to obtain the list of required shared library files:
+# dumpbin (Windows)
+# ldd (Linux/Unix)
+# otool (Mac OSX)
+#
+# The following functions are provided by this script:
+# gp_append_unique
+# is_file_executable
+# gp_item_default_embedded_path
+# (projects can override with gp_item_default_embedded_path_override)
+# gp_resolve_item
+# (projects can override with gp_resolve_item_override)
+# gp_resolved_file_type
+# gp_file_type
+# get_prerequisites
+# list_prerequisites
+# list_prerequisites_by_glob
+#
+# Requires CMake 2.6 or greater because it uses function, break, return and
+# PARENT_SCOPE.
+
+#=============================================================================
+# Copyright 2008-2009 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distributed this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+# gp_append_unique list_var value
+#
+# Append value to the list variable ${list_var} only if the value is not
+# already in the list.
+#
+function(gp_append_unique list_var value)
+ set(contains 0)
+
+ foreach(item ${${list_var}})
+ if("${item}" STREQUAL "${value}")
+ set(contains 1)
+ break()
+ endif("${item}" STREQUAL "${value}")
+ endforeach(item)
+
+ if(NOT contains)
+ set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE)
+ endif(NOT contains)
+endfunction(gp_append_unique)
+
+
+# is_file_executable file result_var
+#
+# Return 1 in ${result_var} if ${file} is a binary executable.
+#
+# Return 0 in ${result_var} otherwise.
+#
+function(is_file_executable file result_var)
+ #
+ # A file is not executable until proven otherwise:
+ #
+ set(${result_var} 0 PARENT_SCOPE)
+
+ get_filename_component(file_full "${file}" ABSOLUTE)
+ string(TOLOWER "${file_full}" file_full_lower)
+
+ # If file name ends in .exe on Windows, *assume* executable:
+ #
+ if(WIN32)
+ if("${file_full_lower}" MATCHES "\\.exe$")
+ set(${result_var} 1 PARENT_SCOPE)
+ return()
+ endif("${file_full_lower}" MATCHES "\\.exe$")
+
+ # A clause could be added here that uses output or return value of dumpbin
+ # to determine ${result_var}. In 99%+? practical cases, the exe name
+ # match will be sufficient...
+ #
+ endif(WIN32)
+
+ # Use the information returned from the Unix shell command "file" to
+ # determine if ${file_full} should be considered an executable file...
+ #
+ # If the file command's output contains "executable" and does *not* contain
+ # "text" then it is likely an executable suitable for prerequisite analysis
+ # via the get_prerequisites macro.
+ #
+ if(UNIX)
+ if(NOT file_cmd)
+ find_program(file_cmd "file")
+ endif(NOT file_cmd)
+
+ if(file_cmd)
+ execute_process(COMMAND "${file_cmd}" "${file_full}"
+ OUTPUT_VARIABLE file_ov
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+
+ # Replace the name of the file in the output with a placeholder token
+ # (the string " _file_full_ ") so that just in case the path name of
+ # the file contains the word "text" or "executable" we are not fooled
+ # into thinking "the wrong thing" because the file name matches the
+ # other 'file' command output we are looking for...
+ #
+ string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}")
+ string(TOLOWER "${file_ov}" file_ov)
+
+ #message(STATUS "file_ov='${file_ov}'")
+ if("${file_ov}" MATCHES "executable")
+ #message(STATUS "executable!")
+ if("${file_ov}" MATCHES "text")
+ #message(STATUS "but text, so *not* a binary executable!")
+ else("${file_ov}" MATCHES "text")
+ set(${result_var} 1 PARENT_SCOPE)
+ return()
+ endif("${file_ov}" MATCHES "text")
+ endif("${file_ov}" MATCHES "executable")
+ else(file_cmd)
+ message(STATUS "warning: No 'file' command, skipping execute_process...")
+ endif(file_cmd)
+ endif(UNIX)
+endfunction(is_file_executable)
+
+
+# gp_item_default_embedded_path item default_embedded_path_var
+#
+# Return the path that others should refer to the item by when the item
+# is embedded inside a bundle.
+#
+# Override on a per-project basis by providing a project-specific
+# gp_item_default_embedded_path_override function.
+#
+function(gp_item_default_embedded_path item default_embedded_path_var)
+
+ # On Windows and Linux, "embed" prerequisites in the same directory
+ # as the executable by default:
+ #
+ set(path "@executable_path")
+ set(overridden 0)
+
+ # On the Mac, relative to the executable depending on the type
+ # of the thing we are embedding:
+ #
+ if(APPLE)
+ #
+ # The assumption here is that all executables in the bundle will be
+ # in same-level-directories inside the bundle. The parent directory
+ # of an executable inside the bundle should be MacOS or a sibling of
+ # MacOS and all embedded paths returned from here will begin with
+ # "@executable_path/../" and will work from all executables in all
+ # such same-level-directories inside the bundle.
+ #
+
+ # By default, embed things right next to the main bundle executable:
+ #
+ set(path "@executable_path/../../Contents/MacOS")
+
+ # Embed .dylibs right next to the main bundle executable:
+ #
+ if(item MATCHES "\\.dylib$")
+ set(path "@executable_path/../MacOS")
+ set(overridden 1)
+ endif(item MATCHES "\\.dylib$")
+
+ # Embed frameworks in the embedded "Frameworks" directory (sibling of MacOS):
+ #
+ if(NOT overridden)
+ if(item MATCHES "[^/]+\\.framework/")
+ set(path "@executable_path/../Frameworks")
+ set(overridden 1)
+ endif(item MATCHES "[^/]+\\.framework/")
+ endif(NOT overridden)
+ endif()
+
+ # Provide a hook so that projects can override the default embedded location
+ # of any given library by whatever logic they choose:
+ #
+ if(COMMAND gp_item_default_embedded_path_override)
+ gp_item_default_embedded_path_override("${item}" path)
+ endif(COMMAND gp_item_default_embedded_path_override)
+
+ set(${default_embedded_path_var} "${path}" PARENT_SCOPE)
+endfunction(gp_item_default_embedded_path)
+
+
+# gp_resolve_item context item exepath dirs resolved_item_var
+#
+# Resolve an item into an existing full path file.
+#
+# Override on a per-project basis by providing a project-specific
+# gp_resolve_item_override function.
+#
+function(gp_resolve_item context item exepath dirs resolved_item_var)
+ set(resolved 0)
+ set(resolved_item "${item}")
+
+ # Is it already resolved?
+ #
+ if(EXISTS "${resolved_item}")
+ set(resolved 1)
+ endif(EXISTS "${resolved_item}")
+
+ if(NOT resolved)
+ if(item MATCHES "@executable_path")
+ #
+ # @executable_path references are assumed relative to exepath
+ #
+ string(REPLACE "@executable_path" "${exepath}" ri "${item}")
+ get_filename_component(ri "${ri}" ABSOLUTE)
+
+ if(EXISTS "${ri}")
+ #message(STATUS "info: embedded item exists (${ri})")
+ set(resolved 1)
+ set(resolved_item "${ri}")
+ else(EXISTS "${ri}")
+ message(STATUS "warning: embedded item does not exist '${ri}'")
+ endif(EXISTS "${ri}")
+ endif(item MATCHES "@executable_path")
+ endif(NOT resolved)
+
+ if(NOT resolved)
+ if(item MATCHES "@loader_path")
+ #
+ # @loader_path references are assumed relative to the
+ # PATH of the given "context" (presumably another library)
+ #
+ get_filename_component(contextpath "${context}" PATH)
+ string(REPLACE "@loader_path" "${contextpath}" ri "${item}")
+ get_filename_component(ri "${ri}" ABSOLUTE)
+
+ if(EXISTS "${ri}")
+ #message(STATUS "info: embedded item exists (${ri})")
+ set(resolved 1)
+ set(resolved_item "${ri}")
+ else(EXISTS "${ri}")
+ message(STATUS "warning: embedded item does not exist '${ri}'")
+ endif(EXISTS "${ri}")
+ endif(item MATCHES "@loader_path")
+ endif(NOT resolved)
+
+ if(NOT resolved)
+ set(ri "ri-NOTFOUND")
+ find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH)
+ find_file(ri "${item}" ${exepath} ${dirs} /usr/lib)
+ if(ri)
+ #message(STATUS "info: 'find_file' in exepath/dirs (${ri})")
+ set(resolved 1)
+ set(resolved_item "${ri}")
+ set(ri "ri-NOTFOUND")
+ endif(ri)
+ endif(NOT resolved)
+
+ if(NOT resolved)
+ if(item MATCHES "[^/]+\\.framework/")
+ set(fw "fw-NOTFOUND")
+ find_file(fw "${item}"
+ "~/Library/Frameworks"
+ "/Library/Frameworks"
+ "/System/Library/Frameworks"
+ )
+ if(fw)
+ #message(STATUS "info: 'find_file' found framework (${fw})")
+ set(resolved 1)
+ set(resolved_item "${fw}")
+ set(fw "fw-NOTFOUND")
+ endif(fw)
+ endif(item MATCHES "[^/]+\\.framework/")
+ endif(NOT resolved)
+
+ # Using find_program on Windows will find dll files that are in the PATH.
+ # (Converting simple file names into full path names if found.)
+ #
+ if(WIN32)
+ if(NOT resolved)
+ set(ri "ri-NOTFOUND")
+ find_program(ri "${item}" PATHS "${exepath};${dirs}" NO_DEFAULT_PATH)
+ find_program(ri "${item}" PATHS "${exepath};${dirs}")
+ if(ri)
+ #message(STATUS "info: 'find_program' in exepath/dirs (${ri})")
+ set(resolved 1)
+ set(resolved_item "${ri}")
+ set(ri "ri-NOTFOUND")
+ endif(ri)
+ endif(NOT resolved)
+ endif(WIN32)
+
+ # Provide a hook so that projects can override item resolution
+ # by whatever logic they choose:
+ #
+ if(COMMAND gp_resolve_item_override)
+ gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved)
+ endif(COMMAND gp_resolve_item_override)
+
+ if(NOT resolved)
+ message(STATUS "
+warning: cannot resolve item '${item}'
+
+ possible problems:
+ need more directories?
+ need to use InstallRequiredSystemLibraries?
+ run in install tree instead of build tree?
+")
+# message(STATUS "
+#******************************************************************************
+#warning: cannot resolve item '${item}'
+#
+# possible problems:
+# need more directories?
+# need to use InstallRequiredSystemLibraries?
+# run in install tree instead of build tree?
+#
+# context='${context}'
+# item='${item}'
+# exepath='${exepath}'
+# dirs='${dirs}'
+# resolved_item_var='${resolved_item_var}'
+#******************************************************************************
+#")
+ endif(NOT resolved)
+
+ set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE)
+endfunction(gp_resolve_item)
+
+
+# gp_resolved_file_type original_file file exepath dirs type_var
+#
+# Return the type of ${file} with respect to ${original_file}. String
+# describing type of prerequisite is returned in variable named ${type_var}.
+#
+# Use ${exepath} and ${dirs} if necessary to resolve non-absolute ${file}
+# values -- but only for non-embedded items.
+#
+# Possible types are:
+# system
+# local
+# embedded
+# other
+#
+function(gp_resolved_file_type original_file file exepath dirs type_var)
+ #message(STATUS "**")
+
+ if(NOT IS_ABSOLUTE "${original_file}")
+ message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file")
+ endif()
+
+ set(is_embedded 0)
+ set(is_local 0)
+ set(is_system 0)
+
+ set(resolved_file "${file}")
+
+ if("${file}" MATCHES "^@(executable|loader)_path")
+ set(is_embedded 1)
+ endif()
+
+ if(NOT is_embedded)
+ if(NOT IS_ABSOLUTE "${file}")
+ gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file)
+ endif()
+
+ string(TOLOWER "${original_file}" original_lower)
+ string(TOLOWER "${resolved_file}" lower)
+
+ if(UNIX)
+ if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11R6/)")
+ set(is_system 1)
+ endif()
+ endif()
+
+ if(APPLE)
+ if(resolved_file MATCHES "^(/System/Library/|/usr/lib/)")
+ set(is_system 1)
+ endif()
+ endif()
+
+ if(WIN32)
+ string(TOLOWER "$ENV{SystemRoot}" sysroot)
+ string(REGEX REPLACE "\\\\" "/" sysroot "${sysroot}")
+
+ string(TOLOWER "$ENV{windir}" windir)
+ string(REGEX REPLACE "\\\\" "/" windir "${windir}")
+
+ if(lower MATCHES "^(${sysroot}/system|${windir}/system|${sysroot}/syswow|${windir}/syswow|(.*/)*msvc[^/]+dll)")
+ set(is_system 1)
+ endif()
+ endif()
+
+ if(NOT is_system)
+ get_filename_component(original_path "${original_lower}" PATH)
+ get_filename_component(path "${lower}" PATH)
+ if("${original_path}" STREQUAL "${path}")
+ set(is_local 1)
+ endif()
+ endif()
+ endif()
+
+ # Return type string based on computed booleans:
+ #
+ set(type "other")
+
+ if(is_system)
+ set(type "system")
+ elseif(is_embedded)
+ set(type "embedded")
+ elseif(is_local)
+ set(type "local")
+ endif()
+
+ #message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'")
+ #message(STATUS " type: '${type}'")
+
+ if(NOT is_embedded)
+ if(NOT IS_ABSOLUTE "${resolved_file}")
+ if(lower MATCHES "^msvc[^/]+dll" AND is_system)
+ message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'")
+ else()
+ message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect")
+ endif()
+ endif()
+ endif()
+
+ set(${type_var} "${type}" PARENT_SCOPE)
+
+ #message(STATUS "**")
+endfunction()
+
+
+# gp_file_type original_file file type_var
+#
+# Return the type of ${file} with respect to ${original_file}. String
+# describing type of prerequisite is returned in variable named ${type_var}.
+#
+# Possible types are:
+# system
+# local
+# embedded
+# other
+#
+function(gp_file_type original_file file type_var)
+ if(NOT IS_ABSOLUTE "${original_file}")
+ message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file")
+ endif()
+
+ get_filename_component(exepath "${original_file}" PATH)
+
+ set(type "")
+ gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type)
+
+ set(${type_var} "${type}" PARENT_SCOPE)
+endfunction(gp_file_type)
+
+
+# get_prerequisites target prerequisites_var exclude_system recurse dirs
+#
+# Get the list of shared library files required by ${target}. The list in
+# the variable named ${prerequisites_var} should be empty on first entry to
+# this function. On exit, ${prerequisites_var} will contain the list of
+# required shared library files.
+#
+# target is the full path to an executable file
+#
+# prerequisites_var is the name of a CMake variable to contain the results
+#
+# exclude_system is 0 or 1: 0 to include "system" prerequisites , 1 to
+# exclude them
+#
+# recurse is 0 or 1: 0 for direct prerequisites only, 1 for all prerequisites
+# recursively
+#
+# exepath is the path to the top level executable used for @executable_path
+# replacment on the Mac
+#
+# dirs is a list of paths where libraries might be found: these paths are
+# searched first when a target without any path info is given. Then standard
+# system locations are also searched: PATH, Framework locations, /usr/lib...
+#
+function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs)
+ set(verbose 0)
+ set(eol_char "E")
+
+ if(NOT IS_ABSOLUTE "${target}")
+ message("warning: target '${target}' is not absolute...")
+ endif(NOT IS_ABSOLUTE "${target}")
+
+ if(NOT EXISTS "${target}")
+ message("warning: target '${target}' does not exist...")
+ endif(NOT EXISTS "${target}")
+
+ # <setup-gp_tool-vars>
+ #
+ # Try to choose the right tool by default. Caller can set gp_tool prior to
+ # calling this function to force using a different tool.
+ #
+ if("${gp_tool}" STREQUAL "")
+ set(gp_tool "ldd")
+ if(APPLE)
+ set(gp_tool "otool")
+ endif(APPLE)
+ if(WIN32)
+ set(gp_tool "dumpbin")
+ endif(WIN32)
+ endif("${gp_tool}" STREQUAL "")
+
+ set(gp_tool_known 0)
+
+ if("${gp_tool}" STREQUAL "ldd")
+ set(gp_cmd_args "")
+ set(gp_regex "^[\t ]*[^\t ]+ => ([^\t ]+).*${eol_char}$")
+ set(gp_regex_cmp_count 1)
+ set(gp_tool_known 1)
+ endif("${gp_tool}" STREQUAL "ldd")
+
+ if("${gp_tool}" STREQUAL "otool")
+ set(gp_cmd_args "-L")
+ set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$")
+ set(gp_regex_cmp_count 3)
+ set(gp_tool_known 1)
+ endif("${gp_tool}" STREQUAL "otool")
+
+ if("${gp_tool}" STREQUAL "dumpbin")
+ set(gp_cmd_args "/dependents")
+ set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$")
+ set(gp_regex_cmp_count 1)
+ set(gp_tool_known 1)
+ set(ENV{VS_UNICODE_OUTPUT} "") # Block extra output from inside VS IDE.
+ endif("${gp_tool}" STREQUAL "dumpbin")
+
+ if(NOT gp_tool_known)
+ message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...")
+ message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'")
+ message(STATUS "Valid gp_tool values are dumpbin, ldd and otool.")
+ return()
+ endif(NOT gp_tool_known)
+
+ set(gp_cmd_paths ${gp_cmd_paths}
+ "C:/Program Files/Microsoft Visual Studio 9.0/VC/bin"
+ "C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin"
+ "C:/Program Files/Microsoft Visual Studio 8/VC/BIN"
+ "C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN"
+ "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN"
+ "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN"
+ "/usr/local/bin"
+ "/usr/bin"
+ )
+
+ find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths})
+
+ if(NOT gp_cmd)
+ message(STATUS "warning: could not find '${gp_tool}' - cannot analyze prerequisites...")
+ return()
+ endif(NOT gp_cmd)
+
+ if("${gp_tool}" STREQUAL "dumpbin")
+ # When running dumpbin, it also needs the "Common7/IDE" directory in the
+ # PATH. It will already be in the PATH if being run from a Visual Studio
+ # command prompt. Add it to the PATH here in case we are running from a
+ # different command prompt.
+ #
+ get_filename_component(gp_cmd_dir "${gp_cmd}" PATH)
+ get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE)
+ if(EXISTS "${gp_cmd_dlls_dir}")
+ # only add to the path if it is not already in the path
+ if(NOT "$ENV{PATH}" MATCHES "${gp_cmd_dlls_dir}")
+ set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}")
+ endif(NOT "$ENV{PATH}" MATCHES "${gp_cmd_dlls_dir}")
+ endif(EXISTS "${gp_cmd_dlls_dir}")
+ endif("${gp_tool}" STREQUAL "dumpbin")
+ #
+ # </setup-gp_tool-vars>
+
+ if("${gp_tool}" STREQUAL "ldd")
+ set(old_ld_env "$ENV{LD_LIBRARY_PATH}")
+ foreach(dir ${exepath} ${dirs})
+ set(ENV{LD_LIBRARY_PATH} "${dir}:$ENV{LD_LIBRARY_PATH}")
+ endforeach(dir)
+ endif("${gp_tool}" STREQUAL "ldd")
+
+
+ # Track new prerequisites at each new level of recursion. Start with an
+ # empty list at each level:
+ #
+ set(unseen_prereqs)
+
+ # Run gp_cmd on the target:
+ #
+ execute_process(
+ COMMAND ${gp_cmd} ${gp_cmd_args} ${target}
+ OUTPUT_VARIABLE gp_cmd_ov
+ )
+
+ if("${gp_tool}" STREQUAL "ldd")
+ set(ENV{LD_LIBRARY_PATH} "${old_ld_env}")
+ endif("${gp_tool}" STREQUAL "ldd")
+
+ if(verbose)
+ message(STATUS "<RawOutput cmd='${gp_cmd} ${gp_cmd_args} ${target}'>")
+ message(STATUS "gp_cmd_ov='${gp_cmd_ov}'")
+ message(STATUS "</RawOutput>")
+ endif(verbose)
+
+ get_filename_component(target_dir "${target}" PATH)
+
+ # Convert to a list of lines:
+ #
+ string(REGEX REPLACE ";" "\\\\;" candidates "${gp_cmd_ov}")
+ string(REGEX REPLACE "\n" "${eol_char};" candidates "${candidates}")
+
+ # Analyze each line for file names that match the regular expression:
+ #
+ foreach(candidate ${candidates})
+ if("${candidate}" MATCHES "${gp_regex}")
+ # Extract information from each candidate:
+ string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}")
+
+ if(gp_regex_cmp_count GREATER 1)
+ string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}")
+ string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}")
+ string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}")
+ string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}")
+ endif(gp_regex_cmp_count GREATER 1)
+
+ if(gp_regex_cmp_count GREATER 2)
+ string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}")
+ string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}")
+ string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}")
+ string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}")
+ endif(gp_regex_cmp_count GREATER 2)
+
+ # Use the raw_item as the list entries returned by this function. Use the
+ # gp_resolve_item function to resolve it to an actual full path file if
+ # necessary.
+ #
+ set(item "${raw_item}")
+
+ # Add each item unless it is excluded:
+ #
+ set(add_item 1)
+
+ if(${exclude_system})
+ set(type "")
+ gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type)
+ if("${type}" STREQUAL "system")
+ set(add_item 0)
+ endif("${type}" STREQUAL "system")
+ endif(${exclude_system})
+
+ if(add_item)
+ list(LENGTH ${prerequisites_var} list_length_before_append)
+ gp_append_unique(${prerequisites_var} "${item}")
+ list(LENGTH ${prerequisites_var} list_length_after_append)
+
+ if(${recurse})
+ # If item was really added, this is the first time we have seen it.
+ # Add it to unseen_prereqs so that we can recursively add *its*
+ # prerequisites...
+ #
+ # But first: resolve its name to an absolute full path name such
+ # that the analysis tools can simply accept it as input.
+ #
+ if(NOT list_length_before_append EQUAL list_length_after_append)
+ gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item)
+ set(unseen_prereqs ${unseen_prereqs} "${resolved_item}")
+ endif(NOT list_length_before_append EQUAL list_length_after_append)
+ endif(${recurse})
+ endif(add_item)
+ else("${candidate}" MATCHES "${gp_regex}")
+ if(verbose)
+ message(STATUS "ignoring non-matching line: '${candidate}'")
+ endif(verbose)
+ endif("${candidate}" MATCHES "${gp_regex}")
+ endforeach(candidate)
+
+ list(LENGTH ${prerequisites_var} prerequisites_var_length)
+ if(prerequisites_var_length GREATER 0)
+ list(SORT ${prerequisites_var})
+ endif(prerequisites_var_length GREATER 0)
+ if(${recurse})
+ set(more_inputs ${unseen_prereqs})
+ foreach(input ${more_inputs})
+ get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}")
+ endforeach(input)
+ endif(${recurse})
+
+ set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE)
+endfunction(get_prerequisites)
+
+
+# list_prerequisites target all exclude_system verbose
+#
+# ARGV0 (target) is the full path to an executable file
+#
+# optional ARGV1 (all) is 0 or 1: 0 for direct prerequisites only,
+# 1 for all prerequisites recursively
+#
+# optional ARGV2 (exclude_system) is 0 or 1: 0 to include "system"
+# prerequisites , 1 to exclude them
+#
+# optional ARGV3 (verbose) is 0 or 1: 0 to print only full path
+# names of prerequisites, 1 to print extra information
+#
+function(list_prerequisites target)
+ if("${ARGV1}" STREQUAL "")
+ set(all 1)
+ else("${ARGV1}" STREQUAL "")
+ set(all "${ARGV1}")
+ endif("${ARGV1}" STREQUAL "")
+
+ if("${ARGV2}" STREQUAL "")
+ set(exclude_system 0)
+ else("${ARGV2}" STREQUAL "")
+ set(exclude_system "${ARGV2}")
+ endif("${ARGV2}" STREQUAL "")
+
+ if("${ARGV3}" STREQUAL "")
+ set(verbose 0)
+ else("${ARGV3}" STREQUAL "")
+ set(verbose "${ARGV3}")
+ endif("${ARGV3}" STREQUAL "")
+
+ set(count 0)
+ set(count_str "")
+ set(print_count "${verbose}")
+ set(print_prerequisite_type "${verbose}")
+ set(print_target "${verbose}")
+ set(type_str "")
+
+ get_filename_component(exepath "${target}" PATH)
+
+ set(prereqs "")
+ get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "")
+
+ if(print_target)
+ message(STATUS "File '${target}' depends on:")
+ endif(print_target)
+
+ foreach(d ${prereqs})
+ math(EXPR count "${count} + 1")
+
+ if(print_count)
+ set(count_str "${count}. ")
+ endif(print_count)
+
+ if(print_prerequisite_type)
+ gp_file_type("${target}" "${d}" type)
+ set(type_str " (${type})")
+ endif(print_prerequisite_type)
+
+ message(STATUS "${count_str}${d}${type_str}")
+ endforeach(d)
+endfunction(list_prerequisites)
+
+
+# list_prerequisites_by_glob glob_arg glob_exp
+#
+# glob_arg is GLOB or GLOB_RECURSE
+#
+# glob_exp is a globbing expression used with "file(GLOB" to retrieve a list
+# of matching files. If a matching file is executable, its prerequisites are
+# listed.
+#
+# Any additional (optional) arguments provided are passed along as the
+# optional arguments to the list_prerequisites calls.
+#
+function(list_prerequisites_by_glob glob_arg glob_exp)
+ message(STATUS "=============================================================================")
+ message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'")
+ message(STATUS "")
+ file(${glob_arg} file_list ${glob_exp})
+ foreach(f ${file_list})
+ is_file_executable("${f}" is_f_executable)
+ if(is_f_executable)
+ message(STATUS "=============================================================================")
+ list_prerequisites("${f}" ${ARGN})
+ message(STATUS "")
+ endif(is_f_executable)
+ endforeach(f)
+endfunction(list_prerequisites_by_glob)
diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake
index 62b764bb30..05f0492234 100644
--- a/indra/cmake/LLAddBuildTest.cmake
+++ b/indra/cmake/LLAddBuildTest.cmake
@@ -1,276 +1,276 @@
-# -*- cmake -*-
-include(LLTestCommand)
-include(GoogleMock)
-
-MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)
- # Given a project name and a list of sourcefiles (with optional properties on each),
- # add targets to build and run the tests specified.
- # ASSUMPTIONS:
- # * this macro is being executed in the project file that is passed in
- # * current working SOURCE dir is that project dir
- # * there is a subfolder tests/ with test code corresponding to the filenames passed in
- # * properties for each sourcefile passed in indicate what libs to link that file with (MAKE NO ASSUMPTIONS ASIDE FROM TUT)
- #
- # More info and examples at: https://wiki.secondlife.com/wiki/How_to_add_unit_tests_to_indra_code
- #
- # WARNING: do NOT modify this code without working with poppy -
- # there is another branch that will conflict heavily with any changes here.
-INCLUDE(GoogleMock)
-
-
- IF(LL_TEST_VERBOSE)
- MESSAGE("LL_ADD_PROJECT_UNIT_TESTS UNITTEST_PROJECT_${project} sources: ${sources}")
- ENDIF(LL_TEST_VERBOSE)
-
- # Start with the header and project-wide setup before making targets
- #project(UNITTEST_PROJECT_${project})
- # Setup includes, paths, etc
- SET(alltest_SOURCE_FILES
- ${CMAKE_SOURCE_DIR}/test/test.cpp
- ${CMAKE_SOURCE_DIR}/test/lltut.cpp
- )
- SET(alltest_DEP_TARGETS
- # needed by the test harness itself
- ${APRUTIL_LIBRARIES}
- ${APR_LIBRARIES}
- llcommon
- )
- IF(NOT "${project}" STREQUAL "llmath")
- # add llmath as a dep unless the tested module *is* llmath!
- LIST(APPEND alltest_DEP_TARGETS
- llmath
- )
- ENDIF(NOT "${project}" STREQUAL "llmath")
- SET(alltest_INCLUDE_DIRS
- ${LLMATH_INCLUDE_DIRS}
- ${LLCOMMON_INCLUDE_DIRS}
- ${LIBS_OPEN_DIR}/test
- ${GOOGLEMOCK_INCLUDE_DIRS}
- )
- SET(alltest_LIBRARIES
- ${GOOGLEMOCK_LIBRARIES}
- ${PTHREAD_LIBRARY}
- ${WINDOWS_LIBRARIES}
- )
- # Headers, for convenience in targets.
- SET(alltest_HEADER_FILES
- ${CMAKE_SOURCE_DIR}/test/test.h
- )
-
- # Use the default flags
- if (LINUX)
- SET(CMAKE_EXE_LINKER_FLAGS "")
- endif (LINUX)
-
- # start the source test executable definitions
- SET(${project}_TEST_OUTPUT "")
- FOREACH (source ${sources})
- STRING( REGEX REPLACE "(.*)\\.[^.]+$" "\\1" name ${source} )
- STRING( REGEX REPLACE ".*\\.([^.]+)$" "\\1" extension ${source} )
- IF(LL_TEST_VERBOSE)
- MESSAGE("LL_ADD_PROJECT_UNIT_TESTS UNITTEST_PROJECT_${project} individual source: ${source} (${name}.${extension})")
- ENDIF(LL_TEST_VERBOSE)
-
- #
- # Per-codefile additional / external source, header, and include dir property extraction
- #
- # Source
- GET_SOURCE_FILE_PROPERTY(${name}_test_additional_SOURCE_FILES ${source} LL_TEST_ADDITIONAL_SOURCE_FILES)
- IF(${name}_test_additional_SOURCE_FILES MATCHES NOTFOUND)
- SET(${name}_test_additional_SOURCE_FILES "")
- ENDIF(${name}_test_additional_SOURCE_FILES MATCHES NOTFOUND)
- SET(${name}_test_SOURCE_FILES ${source} tests/${name}_test.${extension} ${alltest_SOURCE_FILES} ${${name}_test_additional_SOURCE_FILES} )
- IF(LL_TEST_VERBOSE)
- MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_SOURCE_FILES ${${name}_test_SOURCE_FILES}")
- ENDIF(LL_TEST_VERBOSE)
- # Headers
- GET_SOURCE_FILE_PROPERTY(${name}_test_additional_HEADER_FILES ${source} LL_TEST_ADDITIONAL_HEADER_FILES)
- IF(${name}_test_additional_HEADER_FILES MATCHES NOTFOUND)
- SET(${name}_test_additional_HEADER_FILES "")
- ENDIF(${name}_test_additional_HEADER_FILES MATCHES NOTFOUND)
- SET(${name}_test_HEADER_FILES ${name}.h ${${name}_test_additional_HEADER_FILES})
- set_source_files_properties(${${name}_test_HEADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE)
- LIST(APPEND ${name}_test_SOURCE_FILES ${${name}_test_HEADER_FILES})
- IF(LL_TEST_VERBOSE)
- MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_HEADER_FILES ${${name}_test_HEADER_FILES}")
- ENDIF(LL_TEST_VERBOSE)
- # Include dirs
- GET_SOURCE_FILE_PROPERTY(${name}_test_additional_INCLUDE_DIRS ${source} LL_TEST_ADDITIONAL_INCLUDE_DIRS)
- IF(${name}_test_additional_INCLUDE_DIRS MATCHES NOTFOUND)
- SET(${name}_test_additional_INCLUDE_DIRS "")
- ENDIF(${name}_test_additional_INCLUDE_DIRS MATCHES NOTFOUND)
- INCLUDE_DIRECTORIES(${alltest_INCLUDE_DIRS} ${name}_test_additional_INCLUDE_DIRS )
- IF(LL_TEST_VERBOSE)
- MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_INCLUDE_DIRS ${${name}_test_additional_INCLUDE_DIRS}")
- ENDIF(LL_TEST_VERBOSE)
-
-
- # Setup target
- ADD_EXECUTABLE(PROJECT_${project}_TEST_${name} ${${name}_test_SOURCE_FILES})
- SET_TARGET_PROPERTIES(PROJECT_${project}_TEST_${name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}")
-
- #
- # Per-codefile additional / external project dep and lib dep property extraction
- #
- # WARNING: it's REALLY IMPORTANT to not mix these. I guarantee it will not work in the future. + poppy 2009-04-19
- # Projects
- GET_SOURCE_FILE_PROPERTY(${name}_test_additional_PROJECTS ${source} LL_TEST_ADDITIONAL_PROJECTS)
- IF(${name}_test_additional_PROJECTS MATCHES NOTFOUND)
- SET(${name}_test_additional_PROJECTS "")
- ENDIF(${name}_test_additional_PROJECTS MATCHES NOTFOUND)
- # Libraries
- GET_SOURCE_FILE_PROPERTY(${name}_test_additional_LIBRARIES ${source} LL_TEST_ADDITIONAL_LIBRARIES)
- IF(${name}_test_additional_LIBRARIES MATCHES NOTFOUND)
- SET(${name}_test_additional_LIBRARIES "")
- ENDIF(${name}_test_additional_LIBRARIES MATCHES NOTFOUND)
- IF(LL_TEST_VERBOSE)
- MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_PROJECTS ${${name}_test_additional_PROJECTS}")
- MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_LIBRARIES ${${name}_test_additional_LIBRARIES}")
- ENDIF(LL_TEST_VERBOSE)
- # Add to project
- TARGET_LINK_LIBRARIES(PROJECT_${project}_TEST_${name} ${alltest_LIBRARIES} ${alltest_DEP_TARGETS} ${${name}_test_additional_PROJECTS} ${${name}_test_additional_LIBRARIES} )
- # Compile-time Definitions
- GET_SOURCE_FILE_PROPERTY(${name}_test_additional_CFLAGS ${source} LL_TEST_ADDITIONAL_CFLAGS)
- IF(NOT ${name}_test_additional_CFLAGS MATCHES NOTFOUND)
- SET_TARGET_PROPERTIES(PROJECT_${project}_TEST_${name} PROPERTIES COMPILE_FLAGS ${${name}_test_additional_CFLAGS} )
- IF(LL_TEST_VERBOSE)
- MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_CFLAGS ${${name}_test_additional_CFLAGS}")
- ENDIF(LL_TEST_VERBOSE)
- ENDIF(NOT ${name}_test_additional_CFLAGS MATCHES NOTFOUND)
-
- #
- # Setup test targets
- #
- GET_TARGET_PROPERTY(TEST_EXE PROJECT_${project}_TEST_${name} LOCATION)
- SET(TEST_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/PROJECT_${project}_TEST_${name}_ok.txt)
- SET(TEST_CMD ${TEST_EXE} --touch=${TEST_OUTPUT} --sourcedir=${CMAKE_CURRENT_SOURCE_DIR})
-
- # daveh - what configuration does this use? Debug? it's cmake-time, not build time. + poppy 2009-04-19
- IF(LL_TEST_VERBOSE)
- MESSAGE(STATUS "LL_ADD_PROJECT_UNIT_TESTS ${name} test_cmd = ${TEST_CMD}")
- ENDIF(LL_TEST_VERBOSE)
-
- SET_TEST_PATH(LD_LIBRARY_PATH)
- LL_TEST_COMMAND(TEST_SCRIPT_CMD "${LD_LIBRARY_PATH}" ${TEST_CMD})
- IF(LL_TEST_VERBOSE)
- MESSAGE(STATUS "LL_ADD_PROJECT_UNIT_TESTS ${name} test_script = ${TEST_SCRIPT_CMD}")
- ENDIF(LL_TEST_VERBOSE)
- # Add test
- ADD_CUSTOM_COMMAND(
- OUTPUT ${TEST_OUTPUT}
- COMMAND ${TEST_SCRIPT_CMD}
- DEPENDS PROJECT_${project}_TEST_${name}
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- )
- # Why not add custom target and add POST_BUILD command?
- # Slightly less uncertain behavior
- # (OUTPUT commands run non-deterministically AFAIK) + poppy 2009-04-19
- # > I did not use a post build step as I could not make it notify of a
- # > failure after the first time you build and fail a test. - daveh 2009-04-20
- LIST(APPEND ${project}_TEST_OUTPUT ${TEST_OUTPUT})
- ENDFOREACH (source)
-
- # Add the test runner target per-project
- # (replaces old _test_ok targets all over the place)
- ADD_CUSTOM_TARGET(${project}_tests ALL DEPENDS ${${project}_TEST_OUTPUT})
- ADD_DEPENDENCIES(${project} ${project}_tests)
-ENDMACRO(LL_ADD_PROJECT_UNIT_TESTS)
-
-FUNCTION(LL_ADD_INTEGRATION_TEST
- testname
- additional_source_files
- library_dependencies
-# variable args
- )
- if(TEST_DEBUG)
- message(STATUS "Adding INTEGRATION_TEST_${testname} - debug output is on")
- endif(TEST_DEBUG)
-
- SET(source_files
- tests/${testname}_test.cpp
- ${CMAKE_SOURCE_DIR}/test/test.cpp
- ${CMAKE_SOURCE_DIR}/test/lltut.cpp
- ${additional_source_files}
- )
-
- SET(libraries
- ${library_dependencies}
- ${GOOGLEMOCK_LIBRARIES}
- ${PTHREAD_LIBRARY}
- )
-
- # Add test executable build target
- if(TEST_DEBUG)
- message(STATUS "ADD_EXECUTABLE(INTEGRATION_TEST_${testname} ${source_files})")
- endif(TEST_DEBUG)
- ADD_EXECUTABLE(INTEGRATION_TEST_${testname} ${source_files})
- SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}")
- if(STANDALONE)
- SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES COMPILE_FLAGS -I"${TUT_INCLUDE_DIR}")
- endif(STANDALONE)
-
- # Add link deps to the executable
- if(TEST_DEBUG)
- message(STATUS "TARGET_LINK_LIBRARIES(INTEGRATION_TEST_${testname} ${libraries})")
- endif(TEST_DEBUG)
- TARGET_LINK_LIBRARIES(INTEGRATION_TEST_${testname} ${libraries})
-
- # Create the test running command
- SET(test_command ${ARGN})
- GET_TARGET_PROPERTY(TEST_EXE INTEGRATION_TEST_${testname} LOCATION)
- LIST(FIND test_command "{}" test_exe_pos)
- IF(test_exe_pos LESS 0)
- # The {} marker means "the full pathname of the test executable."
- # test_exe_pos -1 means we didn't find it -- so append the test executable
- # name to $ARGN, the variable part of the arg list. This is convenient
- # shorthand for both straightforward execution of the test program (empty
- # $ARGN) and for running a "wrapper" program of some kind accepting the
- # pathname of the test program as the last of its args. You need specify
- # {} only if the test program's pathname isn't the last argument in the
- # desired command line.
- LIST(APPEND test_command "${TEST_EXE}")
- ELSE (test_exe_pos LESS 0)
- # Found {} marker at test_exe_pos. Remove the {}...
- LIST(REMOVE_AT test_command test_exe_pos)
- # ...and replace it with the actual name of the test executable.
- LIST(INSERT test_command test_exe_pos "${TEST_EXE}")
- ENDIF (test_exe_pos LESS 0)
-
- SET_TEST_PATH(LD_LIBRARY_PATH)
- LL_TEST_COMMAND(TEST_SCRIPT_CMD "${LD_LIBRARY_PATH}" ${test_command})
-
- if(TEST_DEBUG)
- message(STATUS "TEST_SCRIPT_CMD: ${TEST_SCRIPT_CMD}")
- endif(TEST_DEBUG)
-
- ADD_CUSTOM_COMMAND(
- TARGET INTEGRATION_TEST_${testname}
- POST_BUILD
- COMMAND ${TEST_SCRIPT_CMD}
- )
-
- # Use CTEST? Not sure how to yet...
- # ADD_TEST(INTEGRATION_TEST_RUNNER_${testname} ${TEST_SCRIPT_CMD})
-
-ENDFUNCTION(LL_ADD_INTEGRATION_TEST)
-
-MACRO(SET_TEST_PATH LISTVAR)
- IF(WINDOWS)
- # We typically build/package only Release variants of third-party
- # libraries, so append the Release staging dir in case the library being
- # sought doesn't have a debug variant.
- set(${LISTVAR} ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR} ${SHARED_LIB_STAGING_DIR}/Release)
- ELSEIF(DARWIN)
- # We typically build/package only Release variants of third-party
- # libraries, so append the Release staging dir in case the library being
- # sought doesn't have a debug variant.
- 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.
- 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)
+# -*- cmake -*-
+include(LLTestCommand)
+include(GoogleMock)
+
+MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)
+ # Given a project name and a list of sourcefiles (with optional properties on each),
+ # add targets to build and run the tests specified.
+ # ASSUMPTIONS:
+ # * this macro is being executed in the project file that is passed in
+ # * current working SOURCE dir is that project dir
+ # * there is a subfolder tests/ with test code corresponding to the filenames passed in
+ # * properties for each sourcefile passed in indicate what libs to link that file with (MAKE NO ASSUMPTIONS ASIDE FROM TUT)
+ #
+ # More info and examples at: https://wiki.secondlife.com/wiki/How_to_add_unit_tests_to_indra_code
+ #
+ # WARNING: do NOT modify this code without working with poppy -
+ # there is another branch that will conflict heavily with any changes here.
+INCLUDE(GoogleMock)
+
+
+ IF(LL_TEST_VERBOSE)
+ MESSAGE("LL_ADD_PROJECT_UNIT_TESTS UNITTEST_PROJECT_${project} sources: ${sources}")
+ ENDIF(LL_TEST_VERBOSE)
+
+ # Start with the header and project-wide setup before making targets
+ #project(UNITTEST_PROJECT_${project})
+ # Setup includes, paths, etc
+ SET(alltest_SOURCE_FILES
+ ${CMAKE_SOURCE_DIR}/test/test.cpp
+ ${CMAKE_SOURCE_DIR}/test/lltut.cpp
+ )
+ SET(alltest_DEP_TARGETS
+ # needed by the test harness itself
+ ${APRUTIL_LIBRARIES}
+ ${APR_LIBRARIES}
+ llcommon
+ )
+ IF(NOT "${project}" STREQUAL "llmath")
+ # add llmath as a dep unless the tested module *is* llmath!
+ LIST(APPEND alltest_DEP_TARGETS
+ llmath
+ )
+ ENDIF(NOT "${project}" STREQUAL "llmath")
+ SET(alltest_INCLUDE_DIRS
+ ${LLMATH_INCLUDE_DIRS}
+ ${LLCOMMON_INCLUDE_DIRS}
+ ${LIBS_OPEN_DIR}/test
+ ${GOOGLEMOCK_INCLUDE_DIRS}
+ )
+ SET(alltest_LIBRARIES
+ ${GOOGLEMOCK_LIBRARIES}
+ ${PTHREAD_LIBRARY}
+ ${WINDOWS_LIBRARIES}
+ )
+ # Headers, for convenience in targets.
+ SET(alltest_HEADER_FILES
+ ${CMAKE_SOURCE_DIR}/test/test.h
+ )
+
+ # Use the default flags
+ if (LINUX)
+ SET(CMAKE_EXE_LINKER_FLAGS "")
+ endif (LINUX)
+
+ # start the source test executable definitions
+ SET(${project}_TEST_OUTPUT "")
+ FOREACH (source ${sources})
+ STRING( REGEX REPLACE "(.*)\\.[^.]+$" "\\1" name ${source} )
+ STRING( REGEX REPLACE ".*\\.([^.]+)$" "\\1" extension ${source} )
+ IF(LL_TEST_VERBOSE)
+ MESSAGE("LL_ADD_PROJECT_UNIT_TESTS UNITTEST_PROJECT_${project} individual source: ${source} (${name}.${extension})")
+ ENDIF(LL_TEST_VERBOSE)
+
+ #
+ # Per-codefile additional / external source, header, and include dir property extraction
+ #
+ # Source
+ GET_SOURCE_FILE_PROPERTY(${name}_test_additional_SOURCE_FILES ${source} LL_TEST_ADDITIONAL_SOURCE_FILES)
+ IF(${name}_test_additional_SOURCE_FILES MATCHES NOTFOUND)
+ SET(${name}_test_additional_SOURCE_FILES "")
+ ENDIF(${name}_test_additional_SOURCE_FILES MATCHES NOTFOUND)
+ SET(${name}_test_SOURCE_FILES ${source} tests/${name}_test.${extension} ${alltest_SOURCE_FILES} ${${name}_test_additional_SOURCE_FILES} )
+ IF(LL_TEST_VERBOSE)
+ MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_SOURCE_FILES ${${name}_test_SOURCE_FILES}")
+ ENDIF(LL_TEST_VERBOSE)
+ # Headers
+ GET_SOURCE_FILE_PROPERTY(${name}_test_additional_HEADER_FILES ${source} LL_TEST_ADDITIONAL_HEADER_FILES)
+ IF(${name}_test_additional_HEADER_FILES MATCHES NOTFOUND)
+ SET(${name}_test_additional_HEADER_FILES "")
+ ENDIF(${name}_test_additional_HEADER_FILES MATCHES NOTFOUND)
+ SET(${name}_test_HEADER_FILES ${name}.h ${${name}_test_additional_HEADER_FILES})
+ set_source_files_properties(${${name}_test_HEADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE)
+ LIST(APPEND ${name}_test_SOURCE_FILES ${${name}_test_HEADER_FILES})
+ IF(LL_TEST_VERBOSE)
+ MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_HEADER_FILES ${${name}_test_HEADER_FILES}")
+ ENDIF(LL_TEST_VERBOSE)
+ # Include dirs
+ GET_SOURCE_FILE_PROPERTY(${name}_test_additional_INCLUDE_DIRS ${source} LL_TEST_ADDITIONAL_INCLUDE_DIRS)
+ IF(${name}_test_additional_INCLUDE_DIRS MATCHES NOTFOUND)
+ SET(${name}_test_additional_INCLUDE_DIRS "")
+ ENDIF(${name}_test_additional_INCLUDE_DIRS MATCHES NOTFOUND)
+ INCLUDE_DIRECTORIES(${alltest_INCLUDE_DIRS} ${name}_test_additional_INCLUDE_DIRS )
+ IF(LL_TEST_VERBOSE)
+ MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_INCLUDE_DIRS ${${name}_test_additional_INCLUDE_DIRS}")
+ ENDIF(LL_TEST_VERBOSE)
+
+
+ # Setup target
+ ADD_EXECUTABLE(PROJECT_${project}_TEST_${name} ${${name}_test_SOURCE_FILES})
+ SET_TARGET_PROPERTIES(PROJECT_${project}_TEST_${name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}")
+
+ #
+ # Per-codefile additional / external project dep and lib dep property extraction
+ #
+ # WARNING: it's REALLY IMPORTANT to not mix these. I guarantee it will not work in the future. + poppy 2009-04-19
+ # Projects
+ GET_SOURCE_FILE_PROPERTY(${name}_test_additional_PROJECTS ${source} LL_TEST_ADDITIONAL_PROJECTS)
+ IF(${name}_test_additional_PROJECTS MATCHES NOTFOUND)
+ SET(${name}_test_additional_PROJECTS "")
+ ENDIF(${name}_test_additional_PROJECTS MATCHES NOTFOUND)
+ # Libraries
+ GET_SOURCE_FILE_PROPERTY(${name}_test_additional_LIBRARIES ${source} LL_TEST_ADDITIONAL_LIBRARIES)
+ IF(${name}_test_additional_LIBRARIES MATCHES NOTFOUND)
+ SET(${name}_test_additional_LIBRARIES "")
+ ENDIF(${name}_test_additional_LIBRARIES MATCHES NOTFOUND)
+ IF(LL_TEST_VERBOSE)
+ MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_PROJECTS ${${name}_test_additional_PROJECTS}")
+ MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_LIBRARIES ${${name}_test_additional_LIBRARIES}")
+ ENDIF(LL_TEST_VERBOSE)
+ # Add to project
+ TARGET_LINK_LIBRARIES(PROJECT_${project}_TEST_${name} ${alltest_LIBRARIES} ${alltest_DEP_TARGETS} ${${name}_test_additional_PROJECTS} ${${name}_test_additional_LIBRARIES} )
+ # Compile-time Definitions
+ GET_SOURCE_FILE_PROPERTY(${name}_test_additional_CFLAGS ${source} LL_TEST_ADDITIONAL_CFLAGS)
+ IF(NOT ${name}_test_additional_CFLAGS MATCHES NOTFOUND)
+ SET_TARGET_PROPERTIES(PROJECT_${project}_TEST_${name} PROPERTIES COMPILE_FLAGS ${${name}_test_additional_CFLAGS} )
+ IF(LL_TEST_VERBOSE)
+ MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_CFLAGS ${${name}_test_additional_CFLAGS}")
+ ENDIF(LL_TEST_VERBOSE)
+ ENDIF(NOT ${name}_test_additional_CFLAGS MATCHES NOTFOUND)
+
+ #
+ # Setup test targets
+ #
+ GET_TARGET_PROPERTY(TEST_EXE PROJECT_${project}_TEST_${name} LOCATION)
+ SET(TEST_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/PROJECT_${project}_TEST_${name}_ok.txt)
+ SET(TEST_CMD ${TEST_EXE} --touch=${TEST_OUTPUT} --sourcedir=${CMAKE_CURRENT_SOURCE_DIR})
+
+ # daveh - what configuration does this use? Debug? it's cmake-time, not build time. + poppy 2009-04-19
+ IF(LL_TEST_VERBOSE)
+ MESSAGE(STATUS "LL_ADD_PROJECT_UNIT_TESTS ${name} test_cmd = ${TEST_CMD}")
+ ENDIF(LL_TEST_VERBOSE)
+
+ SET_TEST_PATH(LD_LIBRARY_PATH)
+ LL_TEST_COMMAND(TEST_SCRIPT_CMD "${LD_LIBRARY_PATH}" ${TEST_CMD})
+ IF(LL_TEST_VERBOSE)
+ MESSAGE(STATUS "LL_ADD_PROJECT_UNIT_TESTS ${name} test_script = ${TEST_SCRIPT_CMD}")
+ ENDIF(LL_TEST_VERBOSE)
+ # Add test
+ ADD_CUSTOM_COMMAND(
+ OUTPUT ${TEST_OUTPUT}
+ COMMAND ${TEST_SCRIPT_CMD}
+ DEPENDS PROJECT_${project}_TEST_${name}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ )
+ # Why not add custom target and add POST_BUILD command?
+ # Slightly less uncertain behavior
+ # (OUTPUT commands run non-deterministically AFAIK) + poppy 2009-04-19
+ # > I did not use a post build step as I could not make it notify of a
+ # > failure after the first time you build and fail a test. - daveh 2009-04-20
+ LIST(APPEND ${project}_TEST_OUTPUT ${TEST_OUTPUT})
+ ENDFOREACH (source)
+
+ # Add the test runner target per-project
+ # (replaces old _test_ok targets all over the place)
+ ADD_CUSTOM_TARGET(${project}_tests ALL DEPENDS ${${project}_TEST_OUTPUT})
+ ADD_DEPENDENCIES(${project} ${project}_tests)
+ENDMACRO(LL_ADD_PROJECT_UNIT_TESTS)
+
+FUNCTION(LL_ADD_INTEGRATION_TEST
+ testname
+ additional_source_files
+ library_dependencies
+# variable args
+ )
+ if(TEST_DEBUG)
+ message(STATUS "Adding INTEGRATION_TEST_${testname} - debug output is on")
+ endif(TEST_DEBUG)
+
+ SET(source_files
+ tests/${testname}_test.cpp
+ ${CMAKE_SOURCE_DIR}/test/test.cpp
+ ${CMAKE_SOURCE_DIR}/test/lltut.cpp
+ ${additional_source_files}
+ )
+
+ SET(libraries
+ ${library_dependencies}
+ ${GOOGLEMOCK_LIBRARIES}
+ ${PTHREAD_LIBRARY}
+ )
+
+ # Add test executable build target
+ if(TEST_DEBUG)
+ message(STATUS "ADD_EXECUTABLE(INTEGRATION_TEST_${testname} ${source_files})")
+ endif(TEST_DEBUG)
+ ADD_EXECUTABLE(INTEGRATION_TEST_${testname} ${source_files})
+ SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}")
+ if(STANDALONE)
+ SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES COMPILE_FLAGS -I"${TUT_INCLUDE_DIR}")
+ endif(STANDALONE)
+
+ # Add link deps to the executable
+ if(TEST_DEBUG)
+ message(STATUS "TARGET_LINK_LIBRARIES(INTEGRATION_TEST_${testname} ${libraries})")
+ endif(TEST_DEBUG)
+ TARGET_LINK_LIBRARIES(INTEGRATION_TEST_${testname} ${libraries})
+
+ # Create the test running command
+ SET(test_command ${ARGN})
+ GET_TARGET_PROPERTY(TEST_EXE INTEGRATION_TEST_${testname} LOCATION)
+ LIST(FIND test_command "{}" test_exe_pos)
+ IF(test_exe_pos LESS 0)
+ # The {} marker means "the full pathname of the test executable."
+ # test_exe_pos -1 means we didn't find it -- so append the test executable
+ # name to $ARGN, the variable part of the arg list. This is convenient
+ # shorthand for both straightforward execution of the test program (empty
+ # $ARGN) and for running a "wrapper" program of some kind accepting the
+ # pathname of the test program as the last of its args. You need specify
+ # {} only if the test program's pathname isn't the last argument in the
+ # desired command line.
+ LIST(APPEND test_command "${TEST_EXE}")
+ ELSE (test_exe_pos LESS 0)
+ # Found {} marker at test_exe_pos. Remove the {}...
+ LIST(REMOVE_AT test_command test_exe_pos)
+ # ...and replace it with the actual name of the test executable.
+ LIST(INSERT test_command test_exe_pos "${TEST_EXE}")
+ ENDIF (test_exe_pos LESS 0)
+
+ SET_TEST_PATH(LD_LIBRARY_PATH)
+ LL_TEST_COMMAND(TEST_SCRIPT_CMD "${LD_LIBRARY_PATH}" ${test_command})
+
+ if(TEST_DEBUG)
+ message(STATUS "TEST_SCRIPT_CMD: ${TEST_SCRIPT_CMD}")
+ endif(TEST_DEBUG)
+
+ ADD_CUSTOM_COMMAND(
+ TARGET INTEGRATION_TEST_${testname}
+ POST_BUILD
+ COMMAND ${TEST_SCRIPT_CMD}
+ )
+
+ # Use CTEST? Not sure how to yet...
+ # ADD_TEST(INTEGRATION_TEST_RUNNER_${testname} ${TEST_SCRIPT_CMD})
+
+ENDFUNCTION(LL_ADD_INTEGRATION_TEST)
+
+MACRO(SET_TEST_PATH LISTVAR)
+ IF(WINDOWS)
+ # We typically build/package only Release variants of third-party
+ # libraries, so append the Release staging dir in case the library being
+ # sought doesn't have a debug variant.
+ set(${LISTVAR} ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR} ${SHARED_LIB_STAGING_DIR}/Release)
+ ELSEIF(DARWIN)
+ # We typically build/package only Release variants of third-party
+ # libraries, so append the Release staging dir in case the library being
+ # sought doesn't have a debug variant.
+ 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.
+ 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)
diff --git a/indra/integration_tests/llui_libtest/llui_libtest.cpp b/indra/integration_tests/llui_libtest/llui_libtest.cpp
index c34115ee80..217e26c3ca 100644
--- a/indra/integration_tests/llui_libtest/llui_libtest.cpp
+++ b/indra/integration_tests/llui_libtest/llui_libtest.cpp
@@ -33,6 +33,7 @@
// linden library includes
#include "llcontrol.h" // LLControlGroup
#include "lldir.h"
+#include "lldiriterator.h"
#include "llerrorcontrol.h"
#include "llfloater.h"
#include "llfontfreetype.h"
@@ -174,7 +175,9 @@ 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))
+
+ LLDirIterator iter(xui_dir, "floater_test_*.xml");
+ while (iter.next(filename))
{
if (filename.find("_new.xml") != std::string::npos)
{
diff --git a/indra/linux_updater/linux_updater.cpp b/indra/linux_updater/linux_updater.cpp
index d909516bf8..808ab3f64f 100644
--- a/indra/linux_updater/linux_updater.cpp
+++ b/indra/linux_updater/linux_updater.cpp
@@ -33,6 +33,7 @@
#include "llerrorcontrol.h"
#include "llfile.h"
#include "lldir.h"
+#include "lldiriterator.h"
#include "llxmlnode.h"
#include "lltrans.h"
@@ -55,6 +56,8 @@ typedef struct _updater_app_state {
std::string strings_dirs;
std::string strings_file;
+ LLDirIterator *image_dir_iter;
+
GtkWidget *window;
GtkWidget *progress_bar;
GtkWidget *image;
@@ -108,7 +111,7 @@ bool translate_init(std::string comma_delim_path_list,
void updater_app_ui_init(void);
void updater_app_quit(UpdaterAppState *app_state);
void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state);
-std::string next_image_filename(std::string& image_path);
+std::string next_image_filename(std::string& image_path, LLDirIterator& iter);
void display_error(GtkWidget *parent, std::string title, std::string message);
BOOL install_package(std::string package_file, std::string destination);
BOOL spawn_viewer(UpdaterAppState *app_state);
@@ -174,7 +177,7 @@ void updater_app_ui_init(UpdaterAppState *app_state)
// load the first image
app_state->image = gtk_image_new_from_file
- (next_image_filename(app_state->image_dir).c_str());
+ (next_image_filename(app_state->image_dir, *app_state->image_dir_iter).c_str());
gtk_widget_set_size_request(app_state->image, 340, 310);
gtk_container_add(GTK_CONTAINER(frame), app_state->image);
@@ -205,7 +208,7 @@ gboolean rotate_image_cb(gpointer data)
llassert(data != NULL);
app_state = (UpdaterAppState *) data;
- filename = next_image_filename(app_state->image_dir);
+ filename = next_image_filename(app_state->image_dir, *app_state->image_dir_iter);
gdk_threads_enter();
gtk_image_set_from_file(GTK_IMAGE(app_state->image), filename.c_str());
@@ -214,10 +217,10 @@ gboolean rotate_image_cb(gpointer data)
return TRUE;
}
-std::string next_image_filename(std::string& image_path)
+std::string next_image_filename(std::string& image_path, LLDirIterator& iter)
{
std::string image_filename;
- gDirUtilp->getNextFileInDir(image_path, "/*.jpg", image_filename);
+ iter.next(image_filename);
return image_path + "/" + image_filename;
}
@@ -741,6 +744,7 @@ void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state)
else if ((!strcmp(argv[i], "--image-dir")) && (++i < argc))
{
app_state->image_dir = argv[i];
+ app_state->image_dir_iter = new LLDirIterator(argv[i], "/*.jpg");
}
else if ((!strcmp(argv[i], "--dest")) && (++i < argc))
{
@@ -825,6 +829,7 @@ int main(int argc, char **argv)
}
bool success = !app_state->failure;
+ delete app_state->image_dir_iter;
delete app_state;
return success ? 0 : 1;
}
diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp
index 8f02391e75..c32a776c3f 100644
--- a/indra/llcommon/llfile.cpp
+++ b/indra/llcommon/llfile.cpp
@@ -92,6 +92,17 @@ LLFILE* LLFile::_fsopen(const std::string& filename, const char* mode, int shari
#endif
}
+int LLFile::close(LLFILE * file)
+{
+ int ret_value = 0;
+ if (file)
+ {
+ ret_value = fclose(file);
+ }
+ return ret_value;
+}
+
+
int LLFile::remove(const std::string& filename)
{
#if LL_WINDOWS
diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h
index 4913af7cb5..dd7d36513a 100644
--- a/indra/llcommon/llfile.h
+++ b/indra/llcommon/llfile.h
@@ -71,6 +71,8 @@ public:
static LLFILE* fopen(const std::string& filename,const char* accessmode); /* Flawfinder: ignore */
static LLFILE* _fsopen(const std::string& filename,const char* accessmode,int sharingFlag);
+ static int close(LLFILE * file);
+
// perms is a permissions mask like 0777 or 0700. In most cases it will
// be overridden by the user's umask. It is ignored on Windows.
static int mkdir(const std::string& filename, int perms = 0700);
diff --git a/indra/llmath/llbbox.cpp b/indra/llmath/llbbox.cpp
index b46a6e03d2..3e2c05a6e6 100644
--- a/indra/llmath/llbbox.cpp
+++ b/indra/llmath/llbbox.cpp
@@ -89,6 +89,19 @@ void LLBBox::addBBoxAgent(const LLBBox& b)
}
}
+LLBBox LLBBox::getAxisAligned() const
+{
+ // no rotation = axis aligned rotation
+ LLBBox aligned(mPosAgent, LLQuaternion(), LLVector3(), LLVector3());
+
+ // add the center point so that it's not empty
+ aligned.addPointAgent(mPosAgent);
+
+ // add our BBox
+ aligned.addBBoxAgent(*this);
+
+ return aligned;
+}
void LLBBox::expand( F32 delta )
{
@@ -147,6 +160,15 @@ BOOL LLBBox::containsPointAgent(const LLVector3& p) const
return containsPointLocal(point_local);
}
+LLVector3 LLBBox::getMinAgent() const
+{
+ return localToAgent(mMinLocal);
+}
+
+LLVector3 LLBBox::getMaxAgent() const
+{
+ return localToAgent(mMaxLocal);
+}
/*
LLBBox operator*(const LLBBox &a, const LLMatrix4 &b)
diff --git a/indra/llmath/llbbox.h b/indra/llmath/llbbox.h
index 5b911793f0..28e69b75e1 100644
--- a/indra/llmath/llbbox.h
+++ b/indra/llmath/llbbox.h
@@ -51,9 +51,11 @@ public:
const LLVector3& getPositionAgent() const { return mPosAgent; }
const LLQuaternion& getRotation() const { return mRotation; }
+ LLVector3 getMinAgent() const;
const LLVector3& getMinLocal() const { return mMinLocal; }
void setMinLocal( const LLVector3& min ) { mMinLocal = min; }
+ LLVector3 getMaxAgent() const;
const LLVector3& getMaxLocal() const { return mMaxLocal; }
void setMaxLocal( const LLVector3& max ) { mMaxLocal = max; }
@@ -80,6 +82,8 @@ public:
LLVector3 localToAgentBasis(const LLVector3& v) const;
LLVector3 agentToLocalBasis(const LLVector3& v) const;
+ // Get the smallest possible axis aligned bbox that contains this bbox
+ LLBBox getAxisAligned() const;
// friend LLBBox operator*(const LLBBox& a, const LLMatrix4& b);
diff --git a/indra/llmessage/llregionflags.h b/indra/llmessage/llregionflags.h
index b9b974ec4f..7b796a0fa8 100644
--- a/indra/llmessage/llregionflags.h
+++ b/indra/llmessage/llregionflags.h
@@ -42,9 +42,6 @@ const U32 REGION_FLAGS_RESET_HOME_ON_TELEPORT = (1 << 3);
// Does the sun move?
const U32 REGION_FLAGS_SUN_FIXED = (1 << 4);
-// Tax free zone (no taxes on objects, land, etc.)
-const U32 REGION_FLAGS_TAX_FREE = (1 << 5);
-
// Can't change the terrain heightfield, even on owned parcels,
// but can plant trees and grass.
const U32 REGION_FLAGS_BLOCK_TERRAFORM = (1 << 6);
@@ -54,17 +51,12 @@ const U32 REGION_FLAGS_BLOCK_LAND_RESELL = (1 << 7);
// All content wiped once per night
const U32 REGION_FLAGS_SANDBOX = (1 << 8);
-const U32 REGION_FLAGS_NULL_LAYER = (1 << 9);
-// const U32 REGION_FLAGS_SKIP_AGENT_ACTION = (1 << 10);
-const U32 REGION_FLAGS_HARD_ALLOW_LAND_TRANSFER = (1 << 10); // Region allows land reselling
-// const U32 REGION_FLAGS_SKIP_UPDATE_INTEREST_LIST= (1 << 11);
-const U32 REGION_FLAGS_HARD_ALLOW_POST_CLASSIFIED = (1 << 11); // Region allows posting of classified ads
const U32 REGION_FLAGS_SKIP_COLLISIONS = (1 << 12); // Pin all non agent rigid bodies
const U32 REGION_FLAGS_SKIP_SCRIPTS = (1 << 13);
const U32 REGION_FLAGS_SKIP_PHYSICS = (1 << 14); // Skip all physics
const U32 REGION_FLAGS_EXTERNALLY_VISIBLE = (1 << 15);
-//const U32 REGION_FLAGS_MAINLAND_VISIBLE = (1 << 16);
-const U32 REGION_FLAGS_PUBLIC_ALLOWED = (1 << 17);
+const U32 REGION_FLAGS_ALLOW_RETURN_ENCROACHING_OBJECT = (1 << 16);
+const U32 REGION_FLAGS_ALLOW_RETURN_ENCROACHING_ESTATE_OBJECT = (1 << 17);
const U32 REGION_FLAGS_BLOCK_DWELL = (1 << 18);
// Is flight allowed?
@@ -81,18 +73,13 @@ const U32 REGION_FLAGS_ESTATE_SKIP_SCRIPTS = (1 << 21);
const U32 REGION_FLAGS_RESTRICT_PUSHOBJECT = (1 << 22);
const U32 REGION_FLAGS_DENY_ANONYMOUS = (1 << 23);
-// const U32 REGION_FLAGS_DENY_IDENTIFIED = (1 << 24);
-// const U32 REGION_FLAGS_DENY_TRANSACTED = (1 << 25);
const U32 REGION_FLAGS_ALLOW_PARCEL_CHANGES = (1 << 26);
-// const U32 REGION_FLAGS_ABUSE_EMAIL_TO_ESTATE_OWNER = (1 << 27); // We no longer support ELAR
-
const U32 REGION_FLAGS_ALLOW_VOICE = (1 << 28);
const U32 REGION_FLAGS_BLOCK_PARCEL_SEARCH = (1 << 29);
const U32 REGION_FLAGS_DENY_AGEUNVERIFIED = (1 << 30);
-const U32 REGION_FLAGS_SKIP_MONO_SCRIPTS = (1 << 31);
const U32 REGION_FLAGS_DEFAULT = REGION_FLAGS_ALLOW_LANDMARK |
REGION_FLAGS_ALLOW_SET_HOME |
@@ -105,7 +92,6 @@ const U32 REGION_FLAGS_PRELUDE_UNSET = REGION_FLAGS_ALLOW_LANDMARK
| REGION_FLAGS_ALLOW_SET_HOME;
const U32 REGION_FLAGS_ESTATE_MASK = REGION_FLAGS_EXTERNALLY_VISIBLE
- | REGION_FLAGS_PUBLIC_ALLOWED
| REGION_FLAGS_SUN_FIXED
| REGION_FLAGS_DENY_ANONYMOUS
| REGION_FLAGS_DENY_AGEUNVERIFIED;
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index d30697e178..c425782715 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -272,9 +272,6 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
initFromParams(p);
- // chrome floaters don't take focus at all
- setFocusRoot(!getIsChrome());
-
initFloater(p);
}
@@ -2910,8 +2907,6 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str
params.from_xui = true;
applyXUILayout(params, parent);
initFromParams(params);
- // chrome floaters don't take focus at all
- setFocusRoot(!getIsChrome());
initFloater(params);
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 6c0d47ef63..32d7be377a 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -1637,6 +1637,10 @@ LLMenuScrollItem::LLMenuScrollItem(const Params& p)
}
LLButton::Params bparams;
+
+ // Disabled the Return key handling by LLMenuScrollItem instead of
+ // passing the key press to the currently selected menu item. See STORM-385.
+ bparams.commit_on_return(false);
bparams.mouse_opaque(true);
bparams.scale_image(false);
bparams.click_callback(p.scroll_callback);
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index 4f7b4be526..9db1feafd1 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -36,6 +36,7 @@
#include "llcachename.h"
#include "lltrans.h"
#include "lluicolortable.h"
+#include "message.h"
#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))"
@@ -684,8 +685,8 @@ std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCa
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");
+ style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor");
+ style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor");
return style_params;
}
@@ -740,6 +741,13 @@ std::string LLUrlEntryObjectIM::getLocation(const std::string &url) const
return LLUrlEntryBase::getLocation(url);
}
+// LLUrlEntryParcel statics.
+LLUUID LLUrlEntryParcel::sAgentID(LLUUID::null);
+LLUUID LLUrlEntryParcel::sSessionID(LLUUID::null);
+LLHost LLUrlEntryParcel::sRegionHost(LLHost::invalid);
+bool LLUrlEntryParcel::sDisconnected(false);
+std::set<LLUrlEntryParcel*> LLUrlEntryParcel::sParcelInfoObservers;
+
///
/// LLUrlEntryParcel Describes a Second Life parcel Url, e.g.,
/// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about
@@ -751,13 +759,88 @@ LLUrlEntryParcel::LLUrlEntryParcel()
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_parcel.xml";
mTooltip = LLTrans::getString("TooltipParcelUrl");
+
+ sParcelInfoObservers.insert(this);
+}
+
+LLUrlEntryParcel::~LLUrlEntryParcel()
+{
+ sParcelInfoObservers.erase(this);
}
std::string LLUrlEntryParcel::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
{
+ LLSD path_array = LLURI(url).pathArray();
+ S32 path_parts = path_array.size();
+
+ if (path_parts < 3) // no parcel id
+ {
+ llwarns << "Failed to parse url [" << url << "]" << llendl;
+ return url;
+ }
+
+ std::string parcel_id_string = unescapeUrl(path_array[2]); // parcel id
+
+ // Add an observer to call LLUrlLabelCallback when we have parcel name.
+ addObserver(parcel_id_string, url, cb);
+
+ LLUUID parcel_id(parcel_id_string);
+
+ sendParcelInfoRequest(parcel_id);
+
return unescapeUrl(url);
}
+void LLUrlEntryParcel::sendParcelInfoRequest(const LLUUID& parcel_id)
+{
+ if (sRegionHost == LLHost::invalid || sDisconnected) return;
+
+ LLMessageSystem *msg = gMessageSystem;
+ msg->newMessage("ParcelInfoRequest");
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, sAgentID );
+ msg->addUUID("SessionID", sSessionID);
+ msg->nextBlock("Data");
+ msg->addUUID("ParcelID", parcel_id);
+ msg->sendReliable(sRegionHost);
+}
+
+void LLUrlEntryParcel::onParcelInfoReceived(const std::string &id, const std::string &label)
+{
+ callObservers(id, label.empty() ? LLTrans::getString("RegionInfoError") : label, mIcon);
+}
+
+// static
+void LLUrlEntryParcel::processParcelInfo(const LLParcelData& parcel_data)
+{
+ std::string label(LLStringUtil::null);
+ if (!parcel_data.name.empty())
+ {
+ label = parcel_data.name;
+ }
+ // If parcel name is empty use Sim_name (x, y, z) for parcel label.
+ else if (!parcel_data.sim_name.empty())
+ {
+ S32 region_x = llround(parcel_data.global_x) % REGION_WIDTH_UNITS;
+ S32 region_y = llround(parcel_data.global_y) % REGION_WIDTH_UNITS;
+ S32 region_z = llround(parcel_data.global_z);
+
+ label = llformat("%s (%d, %d, %d)",
+ parcel_data.sim_name.c_str(), region_x, region_y, region_z);
+ }
+
+ for (std::set<LLUrlEntryParcel*>::iterator iter = sParcelInfoObservers.begin();
+ iter != sParcelInfoObservers.end();
+ ++iter)
+ {
+ LLUrlEntryParcel* url_entry = *iter;
+ if (url_entry)
+ {
+ url_entry->onParcelInfoReceived(parcel_data.parcel_id.asString(), label);
+ }
+ }
+}
+
//
// LLUrlEntryPlace Describes secondlife://<location> URLs
//
diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h
index 1791739061..5f82721c0f 100644
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -31,6 +31,9 @@
#include "lluuid.h"
#include "lluicolor.h"
#include "llstyle.h"
+
+#include "llhost.h" // for resolving parcel name by parcel id
+
#include <boost/signals2.hpp>
#include <boost/regex.hpp>
#include <string>
@@ -285,8 +288,44 @@ private:
class LLUrlEntryParcel : public LLUrlEntryBase
{
public:
+ struct LLParcelData
+ {
+ LLUUID parcel_id;
+ std::string name;
+ std::string sim_name;
+ F32 global_x;
+ F32 global_y;
+ F32 global_z;
+ };
+
LLUrlEntryParcel();
+ ~LLUrlEntryParcel();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+
+ // Sends a parcel info request to sim.
+ void sendParcelInfoRequest(const LLUUID& parcel_id);
+
+ // Calls observers of certain parcel id providing them with parcel label.
+ void onParcelInfoReceived(const std::string &id, const std::string &label);
+
+ // Processes parcel label and triggers notifying observers.
+ static void processParcelInfo(const LLParcelData& parcel_data);
+
+ // Next 4 setters are used to update agent and viewer connection information
+ // upon events like user login, viewer disconnect and user changing region host.
+ // These setters are made public to be accessible from newview and should not be
+ // used in other cases.
+ static void setAgentID(const LLUUID& id) { sAgentID = id; }
+ static void setSessionID(const LLUUID& id) { sSessionID = id; }
+ static void setRegionHost(const LLHost& host) { sRegionHost = host; }
+ static void setDisconnected(bool disconnected) { sDisconnected = disconnected; }
+
+private:
+ static LLUUID sAgentID;
+ static LLUUID sSessionID;
+ static LLHost sRegionHost;
+ static bool sDisconnected;
+ static std::set<LLUrlEntryParcel*> sParcelInfoObservers;
};
///
diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp
index f30704cb22..96ebe83826 100644
--- a/indra/llui/tests/llurlentry_stub.cpp
+++ b/indra/llui/tests/llurlentry_stub.cpp
@@ -30,6 +30,7 @@
#include "llavatarnamecache.h"
#include "llcachename.h"
#include "lluuid.h"
+#include "message.h"
#include <string>
@@ -191,3 +192,20 @@ LLFontGL* LLFontGL::getFontDefault()
{
return NULL;
}
+
+char* _PREHASH_AgentData = "AgentData";
+char* _PREHASH_AgentID = "AgentID";
+
+LLHost LLHost::invalid(INVALID_PORT,INVALID_HOST_IP_ADDRESS);
+
+LLMessageSystem* gMessageSystem = NULL;
+
+//
+// Stub implementation for LLMessageSystem
+//
+void LLMessageSystem::newMessage(const char *name) { }
+void LLMessageSystem::nextBlockFast(const char *blockname) { }
+void LLMessageSystem::nextBlock(const char *blockname) { }
+void LLMessageSystem::addUUIDFast( const char *varname, const LLUUID& uuid) { }
+void LLMessageSystem::addUUID( const char *varname, const LLUUID& uuid) { }
+S32 LLMessageSystem::sendReliable(const LLHost &host) { return 0; }
diff --git a/indra/llvfs/CMakeLists.txt b/indra/llvfs/CMakeLists.txt
index 722f4e2bfd..a3782d824b 100644
--- a/indra/llvfs/CMakeLists.txt
+++ b/indra/llvfs/CMakeLists.txt
@@ -12,6 +12,7 @@ include_directories(
set(llvfs_SOURCE_FILES
lldir.cpp
+ lldiriterator.cpp
lllfsthread.cpp
llpidlock.cpp
llvfile.cpp
@@ -24,6 +25,7 @@ set(llvfs_HEADER_FILES
lldir.h
lldirguard.h
+ lldiriterator.h
lllfsthread.h
llpidlock.h
llvfile.h
@@ -60,6 +62,11 @@ list(APPEND llvfs_SOURCE_FILES ${llvfs_HEADER_FILES})
add_library (llvfs ${llvfs_SOURCE_FILES})
+target_link_libraries(llvfs
+ ${BOOST_FILESYSTEM_LIBRARY}
+ ${BOOST_SYSTEM_LIBRARY}
+ )
+
if (DARWIN)
include(CMakeFindFrameworks)
find_library(CARBON_LIBRARY Carbon)
diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp
index 64556bcb4c..ab7d15dfef 100644
--- a/indra/llvfs/lldir.cpp
+++ b/indra/llvfs/lldir.cpp
@@ -40,6 +40,8 @@
#include "lltimer.h" // ms_sleep()
#include "lluuid.h"
+#include "lldiriterator.h"
+
#if LL_WINDOWS
#include "lldir_win32.h"
LLDir_Win32 gDirUtil;
@@ -83,7 +85,9 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask)
std::string filename;
std::string fullpath;
S32 result;
- while (getNextFileInDir(dirname, mask, filename))
+
+ LLDirIterator iter(dirname, mask);
+ while (iter.next(filename))
{
fullpath = dirname;
fullpath += getDirDelimiter();
diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h
index 42996fd051..5ee8bdb542 100644
--- a/indra/llvfs/lldir.h
+++ b/indra/llvfs/lldir.h
@@ -75,31 +75,6 @@ class LLDir
// pure virtual functions
virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask) = 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;
diff --git a/indra/llvfs/lldir_linux.cpp b/indra/llvfs/lldir_linux.cpp
index 73f2336f94..4ba2f519b0 100644
--- a/indra/llvfs/lldir_linux.cpp
+++ b/indra/llvfs/lldir_linux.cpp
@@ -242,68 +242,6 @@ U32 LLDir_Linux::countFilesInDir(const std::string &dirname, const std::string &
return (file_count);
}
-// get the next file in the directory
-BOOL LLDir_Linux::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
-{
- glob_t g;
- BOOL result = FALSE;
- fname = "";
-
- if(!(dirname == mCurrentDir))
- {
- // different dir specified, close old search
- mCurrentDirIndex = -1;
- mCurrentDirCount = -1;
- mCurrentDir = dirname;
- }
-
- 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)
- {
- if((int)g.gl_pathc != mCurrentDirCount)
- {
- // Number of matches has changed since the last search, meaning a file has been added or deleted.
- // Reset the index.
- mCurrentDirIndex = -1;
- mCurrentDirCount = g.gl_pathc;
- }
-
- mCurrentDirIndex++;
-
- if(mCurrentDirIndex < (int)g.gl_pathc)
- {
-// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl;
-
- // The API wants just the filename, not the full path.
- //fname = g.gl_pathv[mCurrentDirIndex];
-
- char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/');
-
- if(s == NULL)
- s = g.gl_pathv[mCurrentDirIndex];
- else if(s[0] == '/')
- s++;
-
- fname = s;
-
- result = TRUE;
- }
- }
-
- globfree(&g);
- }
-
- return(result);
-}
-
-
-
-
std::string LLDir_Linux::getCurPath()
{
char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */
diff --git a/indra/llvfs/lldir_linux.h b/indra/llvfs/lldir_linux.h
index 451e81ae93..ff4c48759a 100644
--- a/indra/llvfs/lldir_linux.h
+++ b/indra/llvfs/lldir_linux.h
@@ -43,7 +43,6 @@ 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);
/*virtual*/ BOOL fileExists(const std::string &filename) const;
/*virtual*/ std::string getLLPluginLauncher();
diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llvfs/lldir_mac.cpp
index 445285aa43..2d039527c0 100644
--- a/indra/llvfs/lldir_mac.cpp
+++ b/indra/llvfs/lldir_mac.cpp
@@ -258,67 +258,6 @@ U32 LLDir_Mac::countFilesInDir(const std::string &dirname, const std::string &ma
return (file_count);
}
-// get the next file in the directory
-BOOL LLDir_Mac::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
-{
- glob_t g;
- BOOL result = FALSE;
- fname = "";
-
- if(!(dirname == mCurrentDir))
- {
- // different dir specified, close old search
- mCurrentDirIndex = -1;
- mCurrentDirCount = -1;
- mCurrentDir = dirname;
- }
-
- 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)
- {
- if(g.gl_pathc != mCurrentDirCount)
- {
- // Number of matches has changed since the last search, meaning a file has been added or deleted.
- // Reset the index.
- mCurrentDirIndex = -1;
- mCurrentDirCount = g.gl_pathc;
- }
-
- mCurrentDirIndex++;
-
- if(mCurrentDirIndex < g.gl_pathc)
- {
-// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl;
-
- // The API wants just the filename, not the full path.
- //fname = g.gl_pathv[mCurrentDirIndex];
-
- char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/');
-
- if(s == NULL)
- s = g.gl_pathv[mCurrentDirIndex];
- else if(s[0] == '/')
- s++;
-
- fname = s;
-
- result = TRUE;
- }
- }
-
- globfree(&g);
- }
-
- return(result);
-}
-
-
-
S32 LLDir_Mac::deleteFilesInDir(const std::string &dirname, const std::string &mask)
{
glob_t g;
diff --git a/indra/llvfs/lldir_mac.h b/indra/llvfs/lldir_mac.h
index 4eac3c3ae6..e60d5e41c2 100644
--- a/indra/llvfs/lldir_mac.h
+++ b/indra/llvfs/lldir_mac.h
@@ -43,7 +43,6 @@ 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);
virtual BOOL fileExists(const std::string &filename) const;
/*virtual*/ std::string getLLPluginLauncher();
diff --git a/indra/llvfs/lldir_solaris.cpp b/indra/llvfs/lldir_solaris.cpp
index 515fd66b6e..21f8c3acdb 100644
--- a/indra/llvfs/lldir_solaris.cpp
+++ b/indra/llvfs/lldir_solaris.cpp
@@ -260,68 +260,6 @@ U32 LLDir_Solaris::countFilesInDir(const std::string &dirname, const std::string
return (file_count);
}
-// get the next file in the directory
-BOOL LLDir_Solaris::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
-{
- glob_t g;
- BOOL result = FALSE;
- fname = "";
-
- if(!(dirname == mCurrentDir))
- {
- // different dir specified, close old search
- mCurrentDirIndex = -1;
- mCurrentDirCount = -1;
- mCurrentDir = dirname;
- }
-
- 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)
- {
- if((int)g.gl_pathc != mCurrentDirCount)
- {
- // Number of matches has changed since the last search, meaning a file has been added or deleted.
- // Reset the index.
- mCurrentDirIndex = -1;
- mCurrentDirCount = g.gl_pathc;
- }
-
- mCurrentDirIndex++;
-
- if(mCurrentDirIndex < (int)g.gl_pathc)
- {
-// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl;
-
- // The API wants just the filename, not the full path.
- //fname = g.gl_pathv[mCurrentDirIndex];
-
- char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/');
-
- if(s == NULL)
- s = g.gl_pathv[mCurrentDirIndex];
- else if(s[0] == '/')
- s++;
-
- fname = s;
-
- result = TRUE;
- }
- }
-
- globfree(&g);
- }
-
- return(result);
-}
-
-
-
-
std::string LLDir_Solaris::getCurPath()
{
char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */
diff --git a/indra/llvfs/lldir_solaris.h b/indra/llvfs/lldir_solaris.h
index 4a1794f539..f7e1a6301d 100644
--- a/indra/llvfs/lldir_solaris.h
+++ b/indra/llvfs/lldir_solaris.h
@@ -43,7 +43,6 @@ 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);
/*virtual*/ BOOL fileExists(const std::string &filename) const;
private:
diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp
index 33718e520d..2f96fbbbc1 100644
--- a/indra/llvfs/lldir_win32.cpp
+++ b/indra/llvfs/lldir_win32.cpp
@@ -236,67 +236,6 @@ U32 LLDir_Win32::countFilesInDir(const std::string &dirname, const std::string &
return (file_count);
}
-
-// get the next file in the directory
-BOOL LLDir_Win32::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
-{
- BOOL fileFound = FALSE;
- fname = "";
-
- WIN32_FIND_DATAW FileData;
- llutf16string pathname = utf8str_to_utf16str(dirname) + utf8str_to_utf16str(mask);
-
- if (pathname != mCurrentDir)
- {
- // different dir specified, close old search
- if (mCurrentDir[0])
- {
- FindClose(mDirSearch_h);
- }
- mCurrentDir = pathname;
-
- // and open new one
- // Check error opening Directory structure
- if ((mDirSearch_h = FindFirstFile(pathname.c_str(), &FileData)) != INVALID_HANDLE_VALUE)
- {
- fileFound = TRUE;
- }
- }
-
- // Loop to skip over the current (.) and parent (..) directory entries
- // (apparently returned in Win7 but not XP)
- do
- {
- if ( fileFound
- && ( (lstrcmp(FileData.cFileName, (LPCTSTR)TEXT(".")) == 0)
- ||(lstrcmp(FileData.cFileName, (LPCTSTR)TEXT("..")) == 0)
- )
- )
- {
- fileFound = FALSE;
- }
- } while ( mDirSearch_h != INVALID_HANDLE_VALUE
- && !fileFound
- && (fileFound = FindNextFile(mDirSearch_h, &FileData)
- )
- );
-
- if (!fileFound && GetLastError() == ERROR_NO_MORE_FILES)
- {
- // No more files, so reset to beginning of directory
- FindClose(mDirSearch_h);
- mCurrentDir[0] = '\000';
- }
-
- if (fileFound)
- {
- // convert from TCHAR to char
- fname = utf16str_to_utf8str(FileData.cFileName);
- }
-
- return fileFound;
-}
-
std::string LLDir_Win32::getCurPath()
{
WCHAR w_str[MAX_PATH];
diff --git a/indra/llvfs/lldir_win32.h b/indra/llvfs/lldir_win32.h
index 4c932c932c..19c610eb8b 100644
--- a/indra/llvfs/lldir_win32.h
+++ b/indra/llvfs/lldir_win32.h
@@ -40,15 +40,12 @@ 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);
/*virtual*/ BOOL fileExists(const std::string &filename) const;
/*virtual*/ std::string getLLPluginLauncher();
/*virtual*/ std::string getLLPluginFilename(std::string base_name);
private:
- BOOL LLDir_Win32::getNextFileInDir(const llutf16string &dirname, const std::string &mask, std::string &fname);
-
void* mDirSearch_h;
llutf16string mCurrentDir;
};
diff --git a/indra/llvfs/lldiriterator.cpp b/indra/llvfs/lldiriterator.cpp
new file mode 100644
index 0000000000..5536ed8f69
--- /dev/null
+++ b/indra/llvfs/lldiriterator.cpp
@@ -0,0 +1,203 @@
+/**
+ * @file lldiriterator.cpp
+ * @brief Iterator through directory entries matching the search pattern.
+ *
+ * $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 "lldiriterator.h"
+
+#include <boost/filesystem.hpp>
+#include <boost/regex.hpp>
+
+namespace fs = boost::filesystem;
+
+static std::string glob_to_regex(const std::string& glob);
+
+class LLDirIterator::Impl
+{
+public:
+ Impl(const std::string &dirname, const std::string &mask);
+ ~Impl();
+
+ bool next(std::string &fname);
+
+private:
+ boost::regex mFilterExp;
+ fs::directory_iterator mIter;
+ bool mIsValid;
+};
+
+LLDirIterator::Impl::Impl(const std::string &dirname, const std::string &mask)
+ : mIsValid(false)
+{
+ fs::path dir_path(dirname);
+
+ // Check if path exists.
+ if (!fs::exists(dir_path))
+ {
+ llerrs << "Invalid path: \"" << dir_path.string() << "\"" << llendl;
+ return;
+ }
+
+ // Initialize the directory iterator for the given path.
+ try
+ {
+ mIter = fs::directory_iterator(dir_path);
+ }
+ catch (fs::basic_filesystem_error<fs::path>& e)
+ {
+ llerrs << e.what() << llendl;
+ return;
+ }
+
+ // Convert the glob mask to a regular expression
+ std::string exp = glob_to_regex(mask);
+
+ // Initialize boost::regex with the expression converted from
+ // the glob mask.
+ // An exception is thrown if the expression is not valid.
+ try
+ {
+ mFilterExp.assign(exp);
+ }
+ catch (boost::regex_error& e)
+ {
+ llerrs << "\"" << exp << "\" is not a valid regular expression: "
+ << e.what() << llendl;
+ return;
+ }
+
+ mIsValid = true;
+}
+
+LLDirIterator::Impl::~Impl()
+{
+}
+
+bool LLDirIterator::Impl::next(std::string &fname)
+{
+ fname = "";
+
+ if (!mIsValid)
+ {
+ llerrs << "The iterator is not correctly initialized." << llendl;
+ return false;
+ }
+
+ fs::directory_iterator end_itr; // default construction yields past-the-end
+ bool found = false;
+ while (mIter != end_itr && !found)
+ {
+ boost::smatch match;
+ std::string name = mIter->path().filename();
+ if (found = boost::regex_match(name, match, mFilterExp))
+ {
+ fname = name;
+ }
+
+ ++mIter;
+ }
+
+ return found;
+}
+
+std::string glob_to_regex(const std::string& glob)
+{
+ std::string regex;
+ regex.reserve(glob.size()<<1);
+ S32 braces = 0;
+ bool escaped = false;
+ bool square_brace_open = false;
+
+ for (std::string::const_iterator i = glob.begin(); i != glob.end(); ++i)
+ {
+ char c = *i;
+
+ switch (c)
+ {
+ case '.':
+ regex+="\\.";
+ break;
+ case '*':
+ if (glob.begin() == i)
+ {
+ regex+="[^.].*";
+ }
+ else
+ {
+ regex+= escaped ? "*" : ".*";
+ }
+ break;
+ case '?':
+ regex+= escaped ? '?' : '.';
+ break;
+ case '{':
+ braces++;
+ regex+='(';
+ break;
+ case '}':
+ if (!braces)
+ {
+ llerrs << "glob_to_regex: Closing brace without an equivalent opening brace: " << glob << llendl;
+ }
+
+ regex+=')';
+ braces--;
+ break;
+ case ',':
+ regex+= braces ? '|' : c;
+ break;
+ case '!':
+ regex+= square_brace_open ? '^' : c;
+ break;
+ default:
+ regex+=c;
+ break;
+ }
+
+ escaped = ('\\' == c);
+ square_brace_open = ('[' == c);
+ }
+
+ if (braces)
+ {
+ llerrs << "glob_to_regex: Unterminated brace expression: " << glob << llendl;
+ }
+
+ return regex;
+}
+
+LLDirIterator::LLDirIterator(const std::string &dirname, const std::string &mask)
+{
+ mImpl = new Impl(dirname, mask);
+}
+
+LLDirIterator::~LLDirIterator()
+{
+ delete mImpl;
+}
+
+bool LLDirIterator::next(std::string &fname)
+{
+ return mImpl->next(fname);
+}
diff --git a/indra/llvfs/lldiriterator.h b/indra/llvfs/lldiriterator.h
new file mode 100644
index 0000000000..0b48be41b3
--- /dev/null
+++ b/indra/llvfs/lldiriterator.h
@@ -0,0 +1,87 @@
+/**
+ * @file lldiriterator.h
+ * @brief Iterator through directory entries matching the search pattern.
+ *
+ * $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 LL_LLDIRITERATOR_H
+#define LL_LLDIRITERATOR_H
+
+#include "linden_common.h"
+
+/**
+ * Class LLDirIterator
+ *
+ * Iterates through directory entries matching the search pattern.
+ */
+class LLDirIterator
+{
+public:
+ /**
+ * Constructs LLDirIterator object to search for glob pattern
+ * matches in a directory.
+ *
+ * @param dirname - name of a directory to search in.
+ * @param mask - search pattern, a glob expression
+ *
+ * Wildcards supported in glob expressions:
+ * --------------------------------------------------------------
+ * | Wildcard | Matches |
+ * --------------------------------------------------------------
+ * | * |zero or more characters |
+ * | ? |exactly one character |
+ * | [abcde] |exactly one character listed |
+ * | [a-e] |exactly one character in the given range |
+ * | [!abcde] |any character that is not listed |
+ * | [!a-e] |any character that is not in the given range |
+ * | {abc,xyz} |exactly one entire word in the options given |
+ * --------------------------------------------------------------
+ */
+ LLDirIterator(const std::string &dirname, const std::string &mask);
+
+ ~LLDirIterator();
+
+ /**
+ * Searches for the next directory entry matching the glob mask
+ * specified upon iterator construction.
+ * Returns true if a match is found, sets fname
+ * parameter to the name of the matched directory entry and
+ * increments the iterator position.
+ *
+ * Typical usage:
+ * <code>
+ * LLDirIterator iter(directory, pattern);
+ * if ( iter.next(scanResult) )
+ * </code>
+ *
+ * @param fname - name of the matched directory entry.
+ * @return true if a match is found, false otherwise.
+ */
+ bool next(std::string &fname);
+
+protected:
+ class Impl;
+ Impl* mImpl;
+};
+
+#endif //LL_LLDIRITERATOR_H
diff --git a/indra/llvfs/tests/lldir_test.cpp b/indra/llvfs/tests/lldir_test.cpp
index 8788bd63e8..ea321c5ae9 100644
--- a/indra/llvfs/tests/lldir_test.cpp
+++ b/indra/llvfs/tests/lldir_test.cpp
@@ -28,6 +28,7 @@
#include "linden_common.h"
#include "../lldir.h"
+#include "../lldiriterator.h"
#include "../test/lltut.h"
@@ -259,13 +260,12 @@ namespace tut
std::string makeTestFile( const std::string& dir, const std::string& file )
{
- std::string delim = gDirUtilp->getDirDelimiter();
- std::string path = dir + delim + file;
+ std::string path = dir + file;
LLFILE* handle = LLFile::fopen( path, "w" );
ensure("failed to open test file '"+path+"'", handle != NULL );
// Harbison & Steele, 4th ed., p. 366: "If an error occurs, fputs
// returns EOF; otherwise, it returns some other, nonnegative value."
- ensure("failed to write to test file '"+path+"'", fputs("test file", handle) >= 0);
+ ensure("failed to write to test file '"+path+"'", EOF != fputs("test file", handle) );
fclose(handle);
return path;
}
@@ -290,7 +290,7 @@ namespace tut
}
static const char* DirScanFilename[5] = { "file1.abc", "file2.abc", "file1.xyz", "file2.xyz", "file1.mno" };
-
+
void scanTest(const std::string& directory, const std::string& pattern, bool correctResult[5])
{
@@ -300,7 +300,8 @@ namespace tut
bool filesFound[5] = { false, false, false, false, false };
//std::cerr << "searching '"+directory+"' for '"+pattern+"'\n";
- while ( found <= 5 && gDirUtilp->getNextFileInDir(directory, pattern, scanResult) )
+ LLDirIterator iter(directory, pattern);
+ while ( found <= 5 && iter.next(scanResult) )
{
found++;
//std::cerr << " found '"+scanResult+"'\n";
@@ -334,15 +335,15 @@ namespace tut
template<> template<>
void LLDirTest_object_t::test<5>()
- // getNextFileInDir
+ // LLDirIterator::next
{
std::string delim = gDirUtilp->getDirDelimiter();
std::string dirTemp = LLFile::tmpdir();
// Create the same 5 file names of the two directories
- std::string dir1 = makeTestDir(dirTemp + "getNextFileInDir");
- std::string dir2 = makeTestDir(dirTemp + "getNextFileInDir");
+ std::string dir1 = makeTestDir(dirTemp + "LLDirIterator");
+ std::string dir2 = makeTestDir(dirTemp + "LLDirIterator");
std::string dir1files[5];
std::string dir2files[5];
for (int i=0; i<5; i++)
@@ -380,19 +381,17 @@ namespace tut
scanTest(dir2, "file?.x?z", expected7);
// Scan dir2 and see if any file?.??c files are found
- // THESE FAIL ON Mac and Windows, SO ARE COMMENTED OUT FOR NOW
- // bool expected8[5] = { true, true, false, false, false };
- // scanTest(dir2, "file?.??c", expected8);
- // scanTest(dir2, "*.??c", expected8);
+ bool expected8[5] = { true, true, false, false, false };
+ scanTest(dir2, "file?.??c", expected8);
+ scanTest(dir2, "*.??c", expected8);
// Scan dir1 and see if any *.?n? files are found
bool expected9[5] = { false, false, false, false, true };
scanTest(dir1, "*.?n?", expected9);
// Scan dir1 and see if any *.???? files are found
- // THIS ONE FAILS ON WINDOWS (returns three charater suffixes) SO IS COMMENTED OUT FOR NOW
- // bool expected10[5] = { false, false, false, false, false };
- // scanTest(dir1, "*.????", expected10);
+ bool expected10[5] = { false, false, false, false, false };
+ scanTest(dir1, "*.????", expected10);
// Scan dir1 and see if any ?????.* files are found
bool expected11[5] = { true, true, true, true, true };
@@ -402,6 +401,15 @@ namespace tut
bool expected12[5] = { false, false, true, true, false };
scanTest(dir1, "??l??.xyz", expected12);
+ bool expected13[5] = { true, false, true, false, false };
+ scanTest(dir1, "file1.{abc,xyz}", expected13);
+
+ bool expected14[5] = { true, true, false, false, false };
+ scanTest(dir1, "file[0-9].abc", expected14);
+
+ bool expected15[5] = { true, true, false, false, false };
+ scanTest(dir1, "file[!a-z].abc", expected15);
+
// clean up all test files and directories
for (int i=0; i<5; i++)
{
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index a61c35abd2..5d2342e925 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -530,6 +530,7 @@ set(viewer_SOURCE_FILES
llviewerregion.cpp
llviewershadermgr.cpp
llviewerstats.cpp
+ llviewerstatsrecorder.cpp
llviewertexteditor.cpp
llviewertexture.cpp
llviewertextureanim.cpp
@@ -1063,6 +1064,7 @@ set(viewer_HEADER_FILES
llviewerregion.h
llviewershadermgr.h
llviewerstats.h
+ llviewerstatsrecorder.h
llviewertexteditor.h
llviewertexture.h
llviewertextureanim.h
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 77552663ab..7d908df5ce 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -64,6 +64,7 @@
#include "lltool.h"
#include "lltoolmgr.h"
#include "lltrans.h"
+#include "llurlentry.h"
#include "llviewercontrol.h"
#include "llviewerdisplay.h"
#include "llviewerjoystick.h"
@@ -649,6 +650,10 @@ void LLAgent::setRegion(LLViewerRegion *regionp)
}
mRegionp = regionp;
+ // Pass the region host to LLUrlEntryParcel to resolve parcel name
+ // with a server request.
+ LLUrlEntryParcel::setRegionHost(getRegionHost());
+
// Must shift hole-covering water object locations because local
// coordinate frame changed.
LLWorld::getInstance()->updateWaterObjects();
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 80734b0d41..f40fed5ad3 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -1300,8 +1300,16 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id)
return false;
}
- // Check whether the outfit contains the full set of body parts (shape+skin+hair+eyes).
- return getCanMakeFolderIntoOutfit(outfit_cat_id);
+ // Check whether the outfit contains any wearables we aren't wearing already (STORM-702).
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ LLFindWearablesEx is_worn(/*is_worn=*/ false, /*include_body_parts=*/ true);
+ gInventory.collectDescendentsIf(outfit_cat_id,
+ cats,
+ items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_worn);
+ return items.size() > 0;
}
void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category)
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 3a98c23e05..fab6343864 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -44,6 +44,7 @@
#include "llagentwearables.h"
#include "llwindow.h"
#include "llviewerstats.h"
+#include "llviewerstatsrecorder.h"
#include "llmd5.h"
#include "llpumpio.h"
#include "llmimetypes.h"
@@ -89,10 +90,12 @@
// Linden library includes
#include "llavatarnamecache.h"
+#include "lldiriterator.h"
#include "llimagej2c.h"
#include "llmemory.h"
#include "llprimitive.h"
#include "llurlaction.h"
+#include "llurlentry.h"
#include "llvfile.h"
#include "llvfsthread.h"
#include "llvolumemgr.h"
@@ -666,6 +669,10 @@ bool LLAppViewer::init()
mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling"));
+#if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::initClass();
+#endif
+
// *NOTE:Mani - LLCurl::initClass is not thread safe.
// Called before threads are created.
LLCurl::initClass();
@@ -989,6 +996,8 @@ bool LLAppViewer::init()
LLAgentLanguage::init();
+
+
return true;
}
@@ -1709,6 +1718,10 @@ bool LLAppViewer::cleanup()
}
LLMetricPerformanceTesterBasic::cleanClass() ;
+#if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::cleanupClass();
+#endif
+
llinfos << "Cleaning up Media and Textures" << llendflush;
//Note:
@@ -3290,7 +3303,9 @@ void LLAppViewer::migrateCacheDirectory()
S32 file_count = 0;
std::string file_name;
std::string mask = delimiter + "*.*";
- while (gDirUtilp->getNextFileInDir(old_cache_dir, mask, file_name))
+
+ LLDirIterator iter(old_cache_dir, mask);
+ while (iter.next(file_name))
{
if (file_name == "." || file_name == "..") continue;
std::string source_path = old_cache_dir + delimiter + file_name;
@@ -3509,7 +3524,8 @@ bool LLAppViewer::initCache()
dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"");
std::string found_file;
- if (gDirUtilp->getNextFileInDir(dir, mask, found_file))
+ LLDirIterator iter(dir, mask);
+ if (iter.next(found_file))
{
old_vfs_data_file = dir + gDirUtilp->getDirDelimiter() + found_file;
@@ -4567,6 +4583,10 @@ void LLAppViewer::disconnectViewer()
cleanup_xfer_manager();
gDisconnected = TRUE;
+
+ // Pass the connection state to LLUrlEntryParcel not to attempt
+ // parcel info requests while disconnected.
+ LLUrlEntryParcel::setDisconnected(gDisconnected);
}
void LLAppViewer::forceErrorLLError()
diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp
index 898cc1c0ba..fc7a27e5e0 100644
--- a/indra/newview/llappviewerlinux.cpp
+++ b/indra/newview/llappviewerlinux.cpp
@@ -30,6 +30,7 @@
#include "llcommandlineparser.h"
+#include "lldiriterator.h"
#include "llmemtype.h"
#include "llurldispatcher.h" // SLURL from other app instance
#include "llviewernetwork.h"
@@ -504,7 +505,9 @@ std::string LLAppViewerLinux::generateSerialNumber()
// trawl /dev/disk/by-uuid looking for a good-looking UUID to grab
std::string this_name;
- while (gDirUtilp->getNextFileInDir(uuiddir, "*", this_name))
+
+ LLDirIterator iter(uuiddir, "*");
+ while (iter.next(this_name))
{
if (this_name.length() > best.length() ||
(this_name.length() == best.length() &&
diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp
index f12bc16d4b..dd5bc74b2a 100644
--- a/indra/newview/llassetuploadresponders.cpp
+++ b/indra/newview/llassetuploadresponders.cpp
@@ -126,6 +126,7 @@ void LLAssetUploadResponder::error(U32 statusNum, const std::string& reason)
break;
}
LLUploadDialog::modalUploadFinished();
+ LLFilePicker::instance().reset(); // unlock file picker when bulk upload fails
}
//virtual
diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp
index 11b3379814..182d3d23f1 100644
--- a/indra/newview/llfloateruipreview.cpp
+++ b/indra/newview/llfloateruipreview.cpp
@@ -35,6 +35,7 @@
#include "llfloateruipreview.h" // Own header
// Internal utility
+#include "lldiriterator.h"
#include "lleventtimer.h"
#include "llexternaleditor.h"
#include "llrender.h"
@@ -481,9 +482,11 @@ BOOL LLFloaterUIPreview::postBuild()
std::string language_directory;
std::string xui_dir = get_xui_dir(); // directory containing localizations -- don't forget trailing delim
mLanguageSelection->removeall(); // clear out anything temporarily in list from XML
+
+ LLDirIterator iter(xui_dir, "*");
while(found) // for every directory
{
- if((found = gDirUtilp->getNextFileInDir(xui_dir, "*", language_directory))) // get next directory
+ if((found = iter.next(language_directory))) // get next directory
{
std::string full_path = xui_dir + language_directory;
if(LLFile::isfile(full_path.c_str())) // if it's not a directory, skip it
@@ -635,42 +638,51 @@ void LLFloaterUIPreview::refreshList()
mFileList->clearRows(); // empty list
std::string name;
BOOL found = TRUE;
+
+ LLDirIterator floater_iter(getLocalizedDirectory(), "floater_*.xml");
while(found) // for every floater file that matches the pattern
{
- if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "floater_*.xml", name))) // get next file matching pattern
+ if((found = floater_iter.next(name))) // get next file matching pattern
{
addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path)
}
}
found = TRUE;
+
+ LLDirIterator inspect_iter(getLocalizedDirectory(), "inspect_*.xml");
while(found) // for every inspector file that matches the pattern
{
- if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "inspect_*.xml", name))) // get next file matching pattern
+ if((found = inspect_iter.next(name))) // get next file matching pattern
{
addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path)
}
}
found = TRUE;
+
+ LLDirIterator menu_iter(getLocalizedDirectory(), "menu_*.xml");
while(found) // for every menu file that matches the pattern
{
- if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "menu_*.xml", name))) // get next file matching pattern
+ if((found = menu_iter.next(name))) // get next file matching pattern
{
addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path)
}
}
found = TRUE;
+
+ LLDirIterator panel_iter(getLocalizedDirectory(), "panel_*.xml");
while(found) // for every panel file that matches the pattern
{
- if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "panel_*.xml", name))) // get next file matching pattern
+ if((found = panel_iter.next(name))) // get next file matching pattern
{
addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path)
}
}
-
found = TRUE;
+
+ LLDirIterator sidepanel_iter(getLocalizedDirectory(), "sidepanel_*.xml");
while(found) // for every sidepanel file that matches the pattern
{
- if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "sidepanel_*.xml", name))) // get next file matching pattern
+ if((found = sidepanel_iter.next(name))) // get next file matching pattern
{
addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path)
}
diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp
index 51726112a0..058567492b 100644
--- a/indra/newview/llfloaterwebcontent.cpp
+++ b/indra/newview/llfloaterwebcontent.cpp
@@ -1,402 +1,402 @@
-/**
- * @file llfloaterwebcontent.cpp
- * @brief floater for displaying web content - e.g. profiles and search (eventually)
- *
- * $LicenseInfo:firstyear=2006&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llcombobox.h"
-#include "lliconctrl.h"
-#include "llfloaterreg.h"
-#include "lllayoutstack.h"
-#include "llpluginclassmedia.h"
-#include "llprogressbar.h"
-#include "lltextbox.h"
-#include "llurlhistory.h"
-#include "llviewercontrol.h"
-#include "llweb.h"
-#include "llwindow.h"
-
-#include "llfloaterwebcontent.h"
-
-LLFloaterWebContent::LLFloaterWebContent( const LLSD& key )
- : LLFloater( key )
-{
- mCommitCallbackRegistrar.add( "WebContent.Back", boost::bind( &LLFloaterWebContent::onClickBack, this ));
- mCommitCallbackRegistrar.add( "WebContent.Forward", boost::bind( &LLFloaterWebContent::onClickForward, this ));
- mCommitCallbackRegistrar.add( "WebContent.Reload", boost::bind( &LLFloaterWebContent::onClickReload, this ));
- mCommitCallbackRegistrar.add( "WebContent.Stop", boost::bind( &LLFloaterWebContent::onClickStop, this ));
- mCommitCallbackRegistrar.add( "WebContent.EnterAddress", boost::bind( &LLFloaterWebContent::onEnterAddress, this ));
- mCommitCallbackRegistrar.add( "WebContent.PopExternal", boost::bind( &LLFloaterWebContent::onPopExternal, this ));
-}
-
-BOOL LLFloaterWebContent::postBuild()
-{
- // these are used in a bunch of places so cache them
- mWebBrowser = getChild< LLMediaCtrl >( "webbrowser" );
- mAddressCombo = getChild< LLComboBox >( "address" );
- mStatusBarText = getChild< LLTextBox >( "statusbartext" );
- mStatusBarProgress = getChild<LLProgressBar>("statusbarprogress" );
-
- // observe browser events
- mWebBrowser->addObserver( this );
-
- // these buttons are always enabled
- getChildView("reload")->setEnabled( true );
- getChildView("popexternal")->setEnabled( true );
-
- // cache image for secure browsing
- mSecureLockIcon = getChild< LLIconCtrl >("media_secure_lock_flag");
-
- // initialize the URL history using the system URL History manager
- initializeURLHistory();
-
- return TRUE;
-}
-
-void LLFloaterWebContent::initializeURLHistory()
-{
- // start with an empty list
- LLCtrlListInterface* url_list = childGetListInterface("address");
- if (url_list)
- {
- url_list->operateOnAll(LLCtrlListInterface::OP_DELETE);
- }
-
- // Get all of the entries in the "browser" collection
- LLSD browser_history = LLURLHistory::getURLHistory("browser");
- LLSD::array_iterator iter_history =
- browser_history.beginArray();
- LLSD::array_iterator end_history =
- browser_history.endArray();
- for(; iter_history != end_history; ++iter_history)
- {
- std::string url = (*iter_history).asString();
- if(! url.empty())
- url_list->addSimpleElement(url);
- }
-}
-
-//static
-void LLFloaterWebContent::create( const std::string &url, const std::string& target, const std::string& uuid )
-{
- lldebugs << "url = " << url << ", target = " << target << ", uuid = " << uuid << llendl;
-
- std::string tag = target;
-
- if(target.empty() || target == "_blank")
- {
- if(!uuid.empty())
- {
- tag = uuid;
- }
- else
- {
- // create a unique tag for this instance
- LLUUID id;
- id.generate();
- tag = id.asString();
- }
- }
-
- S32 browser_window_limit = gSavedSettings.getS32("WebContentWindowLimit");
-
- if(LLFloaterReg::findInstance("web_content", tag) != NULL)
- {
- // There's already a web browser for this tag, so we won't be opening a new window.
- }
- else if(browser_window_limit != 0)
- {
- // showInstance will open a new window. Figure out how many web browsers are already open,
- // and close the least recently opened one if this will put us over the limit.
-
- LLFloaterReg::const_instance_list_t &instances = LLFloaterReg::getFloaterList("web_content");
- lldebugs << "total instance count is " << instances.size() << llendl;
-
- for(LLFloaterReg::const_instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); iter++)
- {
- lldebugs << " " << (*iter)->getKey() << llendl;
- }
-
- if(instances.size() >= (size_t)browser_window_limit)
- {
- // Destroy the least recently opened instance
- (*instances.begin())->closeFloater();
- }
- }
-
- LLFloaterWebContent *browser = dynamic_cast<LLFloaterWebContent*> (LLFloaterReg::showInstance("web_content", tag));
- llassert(browser);
- if(browser)
- {
- browser->mUUID = uuid;
-
- // tell the browser instance to load the specified URL
- browser->open_media(url, target);
- LLViewerMedia::proxyWindowOpened(target, uuid);
- }
-}
-
-//static
-void LLFloaterWebContent::closeRequest(const std::string &uuid)
-{
- LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content");
- lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl;
- for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
- {
- LLFloaterWebContent* i = dynamic_cast<LLFloaterWebContent*>(*iter);
- lldebugs << " " << i->mUUID << llendl;
- if (i && i->mUUID == uuid)
- {
- i->closeFloater(false);
- return;
- }
- }
-}
-
-//static
-void LLFloaterWebContent::geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height)
-{
- LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content");
- lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl;
- for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
- {
- LLFloaterWebContent* i = dynamic_cast<LLFloaterWebContent*>(*iter);
- lldebugs << " " << i->mUUID << llendl;
- if (i && i->mUUID == uuid)
- {
- i->geometryChanged(x, y, width, height);
- return;
- }
- }
-}
-
-void LLFloaterWebContent::geometryChanged(S32 x, S32 y, S32 width, S32 height)
-{
- // Make sure the layout of the browser control is updated, so this calculation is correct.
- LLLayoutStack::updateClass();
-
- // TODO: need to adjust size and constrain position to make sure floaters aren't moved outside the window view, etc.
- LLCoordWindow window_size;
- getWindow()->getSize(&window_size);
-
- // Adjust width and height for the size of the chrome on the web Browser window.
- width += getRect().getWidth() - mWebBrowser->getRect().getWidth();
- height += getRect().getHeight() - mWebBrowser->getRect().getHeight();
-
- LLRect geom;
- geom.setOriginAndSize(x, window_size.mY - (y + height), width, height);
-
- lldebugs << "geometry change: " << geom << llendl;
-
- handleReshape(geom,false);
-}
-
-void LLFloaterWebContent::open_media(const std::string& web_url, const std::string& target)
-{
- // Specifying a mime type of text/html here causes the plugin system to skip the MIME type probe and just open a browser plugin.
- mWebBrowser->setHomePageUrl(web_url, "text/html");
- mWebBrowser->setTarget(target);
- mWebBrowser->navigateTo(web_url, "text/html");
- set_current_url(web_url);
-}
-
-//virtual
-void LLFloaterWebContent::onClose(bool app_quitting)
-{
- LLViewerMedia::proxyWindowClosed(mUUID);
- destroy();
-}
-
-// virtual
-void LLFloaterWebContent::draw()
-{
- // this is asychronous so we need to keep checking
- getChildView( "back" )->setEnabled( mWebBrowser->canNavigateBack() );
- getChildView( "forward" )->setEnabled( mWebBrowser->canNavigateForward() );
-
- LLFloater::draw();
-}
-
-// virtual
-void LLFloaterWebContent::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
-{
- if(event == MEDIA_EVENT_LOCATION_CHANGED)
- {
- const std::string url = self->getLocation();
-
- if ( url.length() )
- mStatusBarText->setText( url );
-
- set_current_url( url );
- }
- else if(event == MEDIA_EVENT_NAVIGATE_BEGIN)
- {
- // flags are sent with this event
- getChildView("back")->setEnabled( self->getHistoryBackAvailable() );
- getChildView("forward")->setEnabled( self->getHistoryForwardAvailable() );
-
- // toggle visibility of these buttons based on browser state
- getChildView("reload")->setVisible( false );
- getChildView("stop")->setVisible( true );
-
- // turn "on" progress bar now we're about to start loading
- mStatusBarProgress->setVisible( true );
- }
- else if(event == MEDIA_EVENT_NAVIGATE_COMPLETE)
- {
- // flags are sent with this event
- getChildView("back")->setEnabled( self->getHistoryBackAvailable() );
- getChildView("forward")->setEnabled( self->getHistoryForwardAvailable() );
-
- // toggle visibility of these buttons based on browser state
- getChildView("reload")->setVisible( true );
- getChildView("stop")->setVisible( false );
-
- // turn "off" progress bar now we're loaded
- mStatusBarProgress->setVisible( false );
-
- // we populate the status bar with URLs as they change so clear it now we're done
- const std::string end_str = "";
- mStatusBarText->setText( end_str );
-
- // decide if secure browsing icon should be displayed
- std::string prefix = std::string("https://");
- std::string test_prefix = mCurrentURL.substr(0, prefix.length());
- LLStringUtil::toLower(test_prefix);
- if(test_prefix == prefix)
- {
- mSecureLockIcon->setVisible(true);
- }
- else
- {
- mSecureLockIcon->setVisible(false);
- }
- }
- else if(event == MEDIA_EVENT_CLOSE_REQUEST)
- {
- // The browser instance wants its window closed.
- closeFloater();
- }
- else if(event == MEDIA_EVENT_GEOMETRY_CHANGE)
- {
- geometryChanged(self->getGeometryX(), self->getGeometryY(), self->getGeometryWidth(), self->getGeometryHeight());
- }
- else if(event == MEDIA_EVENT_STATUS_TEXT_CHANGED )
- {
- const std::string text = self->getStatusText();
- if ( text.length() )
- mStatusBarText->setText( text );
- }
- else if(event == MEDIA_EVENT_PROGRESS_UPDATED )
- {
- int percent = (int)self->getProgressPercent();
- mStatusBarProgress->setValue( percent );
- }
- else if(event == MEDIA_EVENT_NAME_CHANGED )
- {
- std::string page_title = self->getMediaName();
- // simulate browser behavior - title is empty, use the current URL
- if ( page_title.length() > 0 )
- setTitle( page_title );
- else
- setTitle( mCurrentURL );
- }
- else if(event == MEDIA_EVENT_LINK_HOVERED )
- {
- const std::string link = self->getHoverLink();
- mStatusBarText->setText( link );
- }
-}
-
-void LLFloaterWebContent::set_current_url(const std::string& url)
-{
- mCurrentURL = url;
-
- // serialize url history into the system URL History manager
- LLURLHistory::removeURL("browser", mCurrentURL);
- LLURLHistory::addURL("browser", mCurrentURL);
-
- mAddressCombo->remove( mCurrentURL );
- mAddressCombo->add( mCurrentURL );
- mAddressCombo->selectByValue( mCurrentURL );
-}
-
-void LLFloaterWebContent::onClickForward()
-{
- mWebBrowser->navigateForward();
-}
-
-void LLFloaterWebContent::onClickBack()
-{
- mWebBrowser->navigateBack();
-}
-
-void LLFloaterWebContent::onClickReload()
-{
-
- if( mWebBrowser->getMediaPlugin() )
- {
- bool ignore_cache = true;
- mWebBrowser->getMediaPlugin()->browse_reload( ignore_cache );
- }
- else
- {
- mWebBrowser->navigateTo(mCurrentURL);
- }
-}
-
-void LLFloaterWebContent::onClickStop()
-{
- if( mWebBrowser->getMediaPlugin() )
- mWebBrowser->getMediaPlugin()->browse_stop();
-
- // still should happen when we catch the navigate complete event
- // but sometimes (don't know why) that event isn't sent from Qt
- // and we getto a point where the stop button stays active.
- getChildView("reload")->setVisible( true );
- getChildView("stop")->setVisible( false );
-}
-
-void LLFloaterWebContent::onEnterAddress()
-{
- // make sure there is at least something there.
- // (perhaps this test should be for minimum length of a URL)
- std::string url = mAddressCombo->getValue().asString();
- if ( url.length() > 0 )
- {
- mWebBrowser->navigateTo( url, "text/html");
- };
-}
-
-void LLFloaterWebContent::onPopExternal()
-{
- // make sure there is at least something there.
- // (perhaps this test should be for minimum length of a URL)
- std::string url = mAddressCombo->getValue().asString();
- if ( url.length() > 0 )
- {
- LLWeb::loadURLExternal( url );
- };
-}
+/**
+ * @file llfloaterwebcontent.cpp
+ * @brief floater for displaying web content - e.g. profiles and search (eventually)
+ *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llcombobox.h"
+#include "lliconctrl.h"
+#include "llfloaterreg.h"
+#include "lllayoutstack.h"
+#include "llpluginclassmedia.h"
+#include "llprogressbar.h"
+#include "lltextbox.h"
+#include "llurlhistory.h"
+#include "llviewercontrol.h"
+#include "llweb.h"
+#include "llwindow.h"
+
+#include "llfloaterwebcontent.h"
+
+LLFloaterWebContent::LLFloaterWebContent( const LLSD& key )
+ : LLFloater( key )
+{
+ mCommitCallbackRegistrar.add( "WebContent.Back", boost::bind( &LLFloaterWebContent::onClickBack, this ));
+ mCommitCallbackRegistrar.add( "WebContent.Forward", boost::bind( &LLFloaterWebContent::onClickForward, this ));
+ mCommitCallbackRegistrar.add( "WebContent.Reload", boost::bind( &LLFloaterWebContent::onClickReload, this ));
+ mCommitCallbackRegistrar.add( "WebContent.Stop", boost::bind( &LLFloaterWebContent::onClickStop, this ));
+ mCommitCallbackRegistrar.add( "WebContent.EnterAddress", boost::bind( &LLFloaterWebContent::onEnterAddress, this ));
+ mCommitCallbackRegistrar.add( "WebContent.PopExternal", boost::bind( &LLFloaterWebContent::onPopExternal, this ));
+}
+
+BOOL LLFloaterWebContent::postBuild()
+{
+ // these are used in a bunch of places so cache them
+ mWebBrowser = getChild< LLMediaCtrl >( "webbrowser" );
+ mAddressCombo = getChild< LLComboBox >( "address" );
+ mStatusBarText = getChild< LLTextBox >( "statusbartext" );
+ mStatusBarProgress = getChild<LLProgressBar>("statusbarprogress" );
+
+ // observe browser events
+ mWebBrowser->addObserver( this );
+
+ // these buttons are always enabled
+ getChildView("reload")->setEnabled( true );
+ getChildView("popexternal")->setEnabled( true );
+
+ // cache image for secure browsing
+ mSecureLockIcon = getChild< LLIconCtrl >("media_secure_lock_flag");
+
+ // initialize the URL history using the system URL History manager
+ initializeURLHistory();
+
+ return TRUE;
+}
+
+void LLFloaterWebContent::initializeURLHistory()
+{
+ // start with an empty list
+ LLCtrlListInterface* url_list = childGetListInterface("address");
+ if (url_list)
+ {
+ url_list->operateOnAll(LLCtrlListInterface::OP_DELETE);
+ }
+
+ // Get all of the entries in the "browser" collection
+ LLSD browser_history = LLURLHistory::getURLHistory("browser");
+ LLSD::array_iterator iter_history =
+ browser_history.beginArray();
+ LLSD::array_iterator end_history =
+ browser_history.endArray();
+ for(; iter_history != end_history; ++iter_history)
+ {
+ std::string url = (*iter_history).asString();
+ if(! url.empty())
+ url_list->addSimpleElement(url);
+ }
+}
+
+//static
+void LLFloaterWebContent::create( const std::string &url, const std::string& target, const std::string& uuid )
+{
+ lldebugs << "url = " << url << ", target = " << target << ", uuid = " << uuid << llendl;
+
+ std::string tag = target;
+
+ if(target.empty() || target == "_blank")
+ {
+ if(!uuid.empty())
+ {
+ tag = uuid;
+ }
+ else
+ {
+ // create a unique tag for this instance
+ LLUUID id;
+ id.generate();
+ tag = id.asString();
+ }
+ }
+
+ S32 browser_window_limit = gSavedSettings.getS32("WebContentWindowLimit");
+
+ if(LLFloaterReg::findInstance("web_content", tag) != NULL)
+ {
+ // There's already a web browser for this tag, so we won't be opening a new window.
+ }
+ else if(browser_window_limit != 0)
+ {
+ // showInstance will open a new window. Figure out how many web browsers are already open,
+ // and close the least recently opened one if this will put us over the limit.
+
+ LLFloaterReg::const_instance_list_t &instances = LLFloaterReg::getFloaterList("web_content");
+ lldebugs << "total instance count is " << instances.size() << llendl;
+
+ for(LLFloaterReg::const_instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); iter++)
+ {
+ lldebugs << " " << (*iter)->getKey() << llendl;
+ }
+
+ if(instances.size() >= (size_t)browser_window_limit)
+ {
+ // Destroy the least recently opened instance
+ (*instances.begin())->closeFloater();
+ }
+ }
+
+ LLFloaterWebContent *browser = dynamic_cast<LLFloaterWebContent*> (LLFloaterReg::showInstance("web_content", tag));
+ llassert(browser);
+ if(browser)
+ {
+ browser->mUUID = uuid;
+
+ // tell the browser instance to load the specified URL
+ browser->open_media(url, target);
+ LLViewerMedia::proxyWindowOpened(target, uuid);
+ }
+}
+
+//static
+void LLFloaterWebContent::closeRequest(const std::string &uuid)
+{
+ LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content");
+ lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl;
+ for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
+ {
+ LLFloaterWebContent* i = dynamic_cast<LLFloaterWebContent*>(*iter);
+ lldebugs << " " << i->mUUID << llendl;
+ if (i && i->mUUID == uuid)
+ {
+ i->closeFloater(false);
+ return;
+ }
+ }
+}
+
+//static
+void LLFloaterWebContent::geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height)
+{
+ LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content");
+ lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl;
+ for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
+ {
+ LLFloaterWebContent* i = dynamic_cast<LLFloaterWebContent*>(*iter);
+ lldebugs << " " << i->mUUID << llendl;
+ if (i && i->mUUID == uuid)
+ {
+ i->geometryChanged(x, y, width, height);
+ return;
+ }
+ }
+}
+
+void LLFloaterWebContent::geometryChanged(S32 x, S32 y, S32 width, S32 height)
+{
+ // Make sure the layout of the browser control is updated, so this calculation is correct.
+ LLLayoutStack::updateClass();
+
+ // TODO: need to adjust size and constrain position to make sure floaters aren't moved outside the window view, etc.
+ LLCoordWindow window_size;
+ getWindow()->getSize(&window_size);
+
+ // Adjust width and height for the size of the chrome on the web Browser window.
+ width += getRect().getWidth() - mWebBrowser->getRect().getWidth();
+ height += getRect().getHeight() - mWebBrowser->getRect().getHeight();
+
+ LLRect geom;
+ geom.setOriginAndSize(x, window_size.mY - (y + height), width, height);
+
+ lldebugs << "geometry change: " << geom << llendl;
+
+ handleReshape(geom,false);
+}
+
+void LLFloaterWebContent::open_media(const std::string& web_url, const std::string& target)
+{
+ // Specifying a mime type of text/html here causes the plugin system to skip the MIME type probe and just open a browser plugin.
+ mWebBrowser->setHomePageUrl(web_url, "text/html");
+ mWebBrowser->setTarget(target);
+ mWebBrowser->navigateTo(web_url, "text/html");
+ set_current_url(web_url);
+}
+
+//virtual
+void LLFloaterWebContent::onClose(bool app_quitting)
+{
+ LLViewerMedia::proxyWindowClosed(mUUID);
+ destroy();
+}
+
+// virtual
+void LLFloaterWebContent::draw()
+{
+ // this is asychronous so we need to keep checking
+ getChildView( "back" )->setEnabled( mWebBrowser->canNavigateBack() );
+ getChildView( "forward" )->setEnabled( mWebBrowser->canNavigateForward() );
+
+ LLFloater::draw();
+}
+
+// virtual
+void LLFloaterWebContent::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
+{
+ if(event == MEDIA_EVENT_LOCATION_CHANGED)
+ {
+ const std::string url = self->getLocation();
+
+ if ( url.length() )
+ mStatusBarText->setText( url );
+
+ set_current_url( url );
+ }
+ else if(event == MEDIA_EVENT_NAVIGATE_BEGIN)
+ {
+ // flags are sent with this event
+ getChildView("back")->setEnabled( self->getHistoryBackAvailable() );
+ getChildView("forward")->setEnabled( self->getHistoryForwardAvailable() );
+
+ // toggle visibility of these buttons based on browser state
+ getChildView("reload")->setVisible( false );
+ getChildView("stop")->setVisible( true );
+
+ // turn "on" progress bar now we're about to start loading
+ mStatusBarProgress->setVisible( true );
+ }
+ else if(event == MEDIA_EVENT_NAVIGATE_COMPLETE)
+ {
+ // flags are sent with this event
+ getChildView("back")->setEnabled( self->getHistoryBackAvailable() );
+ getChildView("forward")->setEnabled( self->getHistoryForwardAvailable() );
+
+ // toggle visibility of these buttons based on browser state
+ getChildView("reload")->setVisible( true );
+ getChildView("stop")->setVisible( false );
+
+ // turn "off" progress bar now we're loaded
+ mStatusBarProgress->setVisible( false );
+
+ // we populate the status bar with URLs as they change so clear it now we're done
+ const std::string end_str = "";
+ mStatusBarText->setText( end_str );
+
+ // decide if secure browsing icon should be displayed
+ std::string prefix = std::string("https://");
+ std::string test_prefix = mCurrentURL.substr(0, prefix.length());
+ LLStringUtil::toLower(test_prefix);
+ if(test_prefix == prefix)
+ {
+ mSecureLockIcon->setVisible(true);
+ }
+ else
+ {
+ mSecureLockIcon->setVisible(false);
+ }
+ }
+ else if(event == MEDIA_EVENT_CLOSE_REQUEST)
+ {
+ // The browser instance wants its window closed.
+ closeFloater();
+ }
+ else if(event == MEDIA_EVENT_GEOMETRY_CHANGE)
+ {
+ geometryChanged(self->getGeometryX(), self->getGeometryY(), self->getGeometryWidth(), self->getGeometryHeight());
+ }
+ else if(event == MEDIA_EVENT_STATUS_TEXT_CHANGED )
+ {
+ const std::string text = self->getStatusText();
+ if ( text.length() )
+ mStatusBarText->setText( text );
+ }
+ else if(event == MEDIA_EVENT_PROGRESS_UPDATED )
+ {
+ int percent = (int)self->getProgressPercent();
+ mStatusBarProgress->setValue( percent );
+ }
+ else if(event == MEDIA_EVENT_NAME_CHANGED )
+ {
+ std::string page_title = self->getMediaName();
+ // simulate browser behavior - title is empty, use the current URL
+ if ( page_title.length() > 0 )
+ setTitle( page_title );
+ else
+ setTitle( mCurrentURL );
+ }
+ else if(event == MEDIA_EVENT_LINK_HOVERED )
+ {
+ const std::string link = self->getHoverLink();
+ mStatusBarText->setText( link );
+ }
+}
+
+void LLFloaterWebContent::set_current_url(const std::string& url)
+{
+ mCurrentURL = url;
+
+ // serialize url history into the system URL History manager
+ LLURLHistory::removeURL("browser", mCurrentURL);
+ LLURLHistory::addURL("browser", mCurrentURL);
+
+ mAddressCombo->remove( mCurrentURL );
+ mAddressCombo->add( mCurrentURL );
+ mAddressCombo->selectByValue( mCurrentURL );
+}
+
+void LLFloaterWebContent::onClickForward()
+{
+ mWebBrowser->navigateForward();
+}
+
+void LLFloaterWebContent::onClickBack()
+{
+ mWebBrowser->navigateBack();
+}
+
+void LLFloaterWebContent::onClickReload()
+{
+
+ if( mWebBrowser->getMediaPlugin() )
+ {
+ bool ignore_cache = true;
+ mWebBrowser->getMediaPlugin()->browse_reload( ignore_cache );
+ }
+ else
+ {
+ mWebBrowser->navigateTo(mCurrentURL);
+ }
+}
+
+void LLFloaterWebContent::onClickStop()
+{
+ if( mWebBrowser->getMediaPlugin() )
+ mWebBrowser->getMediaPlugin()->browse_stop();
+
+ // still should happen when we catch the navigate complete event
+ // but sometimes (don't know why) that event isn't sent from Qt
+ // and we getto a point where the stop button stays active.
+ getChildView("reload")->setVisible( true );
+ getChildView("stop")->setVisible( false );
+}
+
+void LLFloaterWebContent::onEnterAddress()
+{
+ // make sure there is at least something there.
+ // (perhaps this test should be for minimum length of a URL)
+ std::string url = mAddressCombo->getValue().asString();
+ if ( url.length() > 0 )
+ {
+ mWebBrowser->navigateTo( url, "text/html");
+ };
+}
+
+void LLFloaterWebContent::onPopExternal()
+{
+ // make sure there is at least something there.
+ // (perhaps this test should be for minimum length of a URL)
+ std::string url = mAddressCombo->getValue().asString();
+ if ( url.length() > 0 )
+ {
+ LLWeb::loadURLExternal( url );
+ };
+}
diff --git a/indra/newview/llfloaterwebcontent.h b/indra/newview/llfloaterwebcontent.h
index 001d822ada..ecc7e970d8 100644
--- a/indra/newview/llfloaterwebcontent.h
+++ b/indra/newview/llfloaterwebcontent.h
@@ -1,82 +1,82 @@
-/**
- * @file llfloaterwebcontent.h
- * @brief floater for displaying web content - e.g. profiles and search (eventually)
- *
- * $LicenseInfo:firstyear=2006&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLFLOATERWEBCONTENT_H
-#define LL_LLFLOATERWEBCONTENT_H
-
-#include "llfloater.h"
-#include "llmediactrl.h"
-
-class LLMediaCtrl;
-class LLComboBox;
-class LLTextBox;
-class LLProgressBar;
-class LLIconCtrl;
-
-class LLFloaterWebContent :
- public LLFloater,
- public LLViewerMediaObserver
-{
-public:
- LOG_CLASS(LLFloaterWebContent);
- LLFloaterWebContent(const LLSD& key);
-
+/**
+ * @file llfloaterwebcontent.h
+ * @brief floater for displaying web content - e.g. profiles and search (eventually)
+ *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLOATERWEBCONTENT_H
+#define LL_LLFLOATERWEBCONTENT_H
+
+#include "llfloater.h"
+#include "llmediactrl.h"
+
+class LLMediaCtrl;
+class LLComboBox;
+class LLTextBox;
+class LLProgressBar;
+class LLIconCtrl;
+
+class LLFloaterWebContent :
+ public LLFloater,
+ public LLViewerMediaObserver
+{
+public:
+ LOG_CLASS(LLFloaterWebContent);
+ LLFloaterWebContent(const LLSD& key);
+
void initializeURLHistory();
-
- static void create(const std::string &url, const std::string& target, const std::string& uuid = LLStringUtil::null);
-
- static void closeRequest(const std::string &uuid);
- static void geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height);
- void geometryChanged(S32 x, S32 y, S32 width, S32 height);
-
- /* virtual */ BOOL postBuild();
- /* virtual */ void onClose(bool app_quitting);
- /* virtual */ void draw();
-
- // inherited from LLViewerMediaObserver
- /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
-
- void onClickBack();
- void onClickForward();
- void onClickReload();
- void onClickStop();
- void onEnterAddress();
- void onPopExternal();
-
-private:
- void open_media(const std::string& media_url, const std::string& target);
- void set_current_url(const std::string& url);
-
- LLMediaCtrl* mWebBrowser;
- LLComboBox* mAddressCombo;
- LLIconCtrl *mSecureLockIcon;
- LLTextBox* mStatusBarText;
- LLProgressBar* mStatusBarProgress;
- std::string mCurrentURL;
- std::string mUUID;
-};
-
-#endif // LL_LLFLOATERWEBCONTENT_H
+
+ static void create(const std::string &url, const std::string& target, const std::string& uuid = LLStringUtil::null);
+
+ static void closeRequest(const std::string &uuid);
+ static void geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height);
+ void geometryChanged(S32 x, S32 y, S32 width, S32 height);
+
+ /* virtual */ BOOL postBuild();
+ /* virtual */ void onClose(bool app_quitting);
+ /* virtual */ void draw();
+
+ // inherited from LLViewerMediaObserver
+ /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
+
+ void onClickBack();
+ void onClickForward();
+ void onClickReload();
+ void onClickStop();
+ void onEnterAddress();
+ void onPopExternal();
+
+private:
+ void open_media(const std::string& media_url, const std::string& target);
+ void set_current_url(const std::string& url);
+
+ LLMediaCtrl* mWebBrowser;
+ LLComboBox* mAddressCombo;
+ LLIconCtrl *mSecureLockIcon;
+ LLTextBox* mStatusBarText;
+ LLProgressBar* mStatusBarProgress;
+ std::string mCurrentURL;
+ std::string mUUID;
+};
+
+#endif // LL_LLFLOATERWEBCONTENT_H
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index ce305dcd89..afd565bb26 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -280,19 +280,19 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string&
void LLIMModel::LLIMSession::onAdHocNameCache(const LLAvatarName& av_name)
{
if (av_name.mIsDummy)
- {
- S32 separator_index = mName.rfind(" ");
- std::string name = mName.substr(0, separator_index);
- ++separator_index;
- std::string conference_word = mName.substr(separator_index, mName.length());
-
- // additional check that session name is what we expected
- if ("Conference" == conference_word)
- {
- LLStringUtil::format_map_t args;
- args["[AGENT_NAME]"] = name;
- LLTrans::findString(mName, "conference-title-incoming", args);
- }
+ {
+ S32 separator_index = mName.rfind(" ");
+ std::string name = mName.substr(0, separator_index);
+ ++separator_index;
+ std::string conference_word = mName.substr(separator_index, mName.length());
+
+ // additional check that session name is what we expected
+ if ("Conference" == conference_word)
+ {
+ LLStringUtil::format_map_t args;
+ args["[AGENT_NAME]"] = name;
+ LLTrans::findString(mName, "conference-title-incoming", args);
+ }
}
else
{
diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h
index e765a8da2f..a15776c207 100644
--- a/indra/newview/llimview.h
+++ b/indra/newview/llimview.h
@@ -100,7 +100,7 @@ public:
void onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name);
- void onAdHocNameCache(const LLAvatarName& av_name);
+ void onAdHocNameCache(const LLAvatarName& av_name);
//*TODO make private
static std::string generateHash(const std::set<LLUUID>& sorted_uuids);
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index ef20869114..61d0a150b7 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -686,6 +686,12 @@ bool LLFindWearablesEx::operator()(LLInventoryCategory* cat, LLInventoryItem* it
return false;
}
+ // Skip broken links.
+ if (vitem->getIsBrokenLink())
+ {
+ return false;
+ }
+
return (bool) get_is_item_worn(item->getUUID()) == mIsWorn;
}
diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp
index 1527f8f4c9..55164f6094 100644
--- a/indra/newview/lllocationinputctrl.cpp
+++ b/indra/newview/lllocationinputctrl.cpp
@@ -547,6 +547,10 @@ void LLLocationInputCtrl::onFocusLost()
{
LLUICtrl::onFocusLost();
refreshLocation();
+
+ // Setting cursor to 0 to show the left edge of the text. See STORM-370.
+ mTextEntry->setCursor(0);
+
if(mTextEntry->hasSelection()){
mTextEntry->deselect();
}
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp
index 0121bbb1ed..b09cfbe907 100644
--- a/indra/newview/lllogchat.cpp
+++ b/indra/newview/lllogchat.cpp
@@ -32,6 +32,7 @@
#include "lltrans.h"
#include "llviewercontrol.h"
+#include "lldiriterator.h"
#include "llinstantmessage.h"
#include "llsingleton.h" // for LLSingleton
@@ -89,15 +90,15 @@ const static boost::regex TIMESTAMP_AND_STUFF("^(\\[\\d{4}/\\d{1,2}/\\d{1,2}\\s+
*/
const static boost::regex NAME_AND_TEXT("([^:]+[:]{1})?(\\s*)(.*)");
-/**
- * These are recognizers for matching the names of ad-hoc conferences when generating the log file name
- * On invited side, an ad-hoc is named like "<first name> <last name> Conference 2010/11/19 03:43 f0f4"
- * On initiating side, an ad-hoc is named like Ad-hoc Conference hash<hash>"
- * If the naming system for ad-hoc conferences are change in LLIMModel::LLIMSession::buildHistoryFileName()
- * then these definition need to be adjusted as well.
- */
-const static boost::regex INBOUND_CONFERENCE("^[a-zA-Z]{1,31} [a-zA-Z]{1,31} Conference [0-9]{4}/[0-9]{2}/[0-9]{2} [0-9]{2}:[0-9]{2} [0-9a-f]{4}");
-const static boost::regex OUTBOUND_CONFERENCE("^Ad-hoc Conference hash[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}");
+/**
+ * These are recognizers for matching the names of ad-hoc conferences when generating the log file name
+ * On invited side, an ad-hoc is named like "<first name> <last name> Conference 2010/11/19 03:43 f0f4"
+ * On initiating side, an ad-hoc is named like Ad-hoc Conference hash<hash>"
+ * If the naming system for ad-hoc conferences are change in LLIMModel::LLIMSession::buildHistoryFileName()
+ * then these definition need to be adjusted as well.
+ */
+const static boost::regex INBOUND_CONFERENCE("^[a-zA-Z]{1,31} [a-zA-Z]{1,31} Conference [0-9]{4}/[0-9]{2}/[0-9]{2} [0-9]{2}:[0-9]{2} [0-9a-f]{4}");
+const static boost::regex OUTBOUND_CONFERENCE("^Ad-hoc Conference hash[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}");
//is used to parse complex object names like "Xstreet SL Terminal v2.2.5 st"
const static std::string NAME_TEXT_DIVIDER(": ");
@@ -601,7 +602,8 @@ std::string LLLogChat::oldLogFileName(std::string filename)
//LL_INFOS("") << "Checking:" << directory << " for " << pattern << LL_ENDL;/* uncomment if you want to verify step, delete on commit */
std::vector<std::string> allfiles;
- while (gDirUtilp->getNextFileInDir(directory, pattern, scanResult))
+ LLDirIterator iter(directory, pattern);
+ while (iter.next(scanResult))
{
//LL_INFOS("") << "Found :" << scanResult << LL_ENDL;
allfiles.push_back(scanResult);
diff --git a/indra/newview/llpanelme.cpp b/indra/newview/llpanelme.cpp
index 5ea94e0611..d3c9c3e131 100644
--- a/indra/newview/llpanelme.cpp
+++ b/indra/newview/llpanelme.cpp
@@ -76,17 +76,19 @@ void LLPanelMe::onOpen(const LLSD& key)
{
LLPanelProfile::onOpen(key);
- // Force Edit My Profile if this is the first time when user is opening Me Panel (EXT-5068)
- bool opened = gSavedSettings.getBOOL("MePanelOpened");
- // In some cases Side Tray my call onOpen() twice, check getCollapsed() to be sure this
- // is the last time onOpen() is called
- if( !opened && !LLSideTray::getInstance()->getCollapsed() )
- {
- buildEditPanel();
- openPanel(mEditPanel, getAvatarId());
-
- gSavedSettings.setBOOL("MePanelOpened", true);
- }
+ // Removed this action as per SOCIAL-431 The first time a new resident opens the profile tab
+ // in the sidebar, they see the old profile editing panel
+ //
+ //// Force Edit My Profile if this is the first time when user is opening Me Panel (EXT-5068)
+ //bool opened = gSavedSettings.getBOOL("MePanelOpened");
+ //// In some cases Side Tray my call onOpen() twice, check getCollapsed() to be sure this
+ //// is the last time onOpen() is called
+ //if( !opened && !LLSideTray::getInstance()->getCollapsed() )
+ //{
+ // buildEditPanel();
+ // openPanel(mEditPanel, getAvatarId());
+ // gSavedSettings.setBOOL("MePanelOpened", true);
+ //}
}
bool LLPanelMe::notifyChildren(const LLSD& info)
diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp
index e5ef51bdd1..3862dac340 100644
--- a/indra/newview/llremoteparcelrequest.cpp
+++ b/indra/newview/llremoteparcelrequest.cpp
@@ -33,6 +33,7 @@
#include "llpanel.h"
#include "llhttpclient.h"
#include "llsdserialize.h"
+#include "llurlentry.h"
#include "llviewerregion.h"
#include "llview.h"
@@ -168,6 +169,18 @@ void LLRemoteParcelInfoProcessor::processParcelInfoReply(LLMessageSystem* msg, v
{
observers.erase(*i);
}
+
+ LLUrlEntryParcel::LLParcelData url_data;
+ url_data.parcel_id = parcel_data.parcel_id;
+ url_data.name = parcel_data.name;
+ url_data.sim_name = parcel_data.sim_name;
+ url_data.global_x = parcel_data.global_x;
+ url_data.global_y = parcel_data.global_y;
+ url_data.global_z = parcel_data.global_z;
+
+ // Pass the parcel data to LLUrlEntryParcel to render
+ // human readable parcel name.
+ LLUrlEntryParcel::processParcelInfo(url_data);
}
void LLRemoteParcelInfoProcessor::sendParcelInfoRequest(const LLUUID& parcel_id)
diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp
index aef665a35c..19d1bdee86 100644
--- a/indra/newview/llsidetray.cpp
+++ b/indra/newview/llsidetray.cpp
@@ -498,8 +498,8 @@ private:
LLSideTray::Params::Params()
: collapsed("collapsed",false),
- tab_btn_image_normal("tab_btn_image",LLUI::getUIImage("sidebar_tab_left.tga")),
- tab_btn_image_selected("tab_btn_image_selected",LLUI::getUIImage("button_enabled_selected_32x128.tga")),
+ tab_btn_image_normal("tab_btn_image",LLUI::getUIImage("taskpanel/TaskPanel_Tab_Off.png")),
+ tab_btn_image_selected("tab_btn_image_selected",LLUI::getUIImage("taskpanel/TaskPanel_Tab_Selected.png")),
default_button_width("tab_btn_width",32),
default_button_height("tab_btn_height",32),
default_button_margin("tab_btn_margin",0)
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 960e72ee42..8adb8c30e0 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -2578,6 +2578,49 @@ void renderCrossHairs(LLVector3 position, F32 size, LLColor4 color)
gGL.end();
}
+void renderUpdateType(LLDrawable* drawablep)
+{
+ LLViewerObject* vobj = drawablep->getVObj();
+ if (!vobj || OUT_UNKNOWN == vobj->getLastUpdateType())
+ {
+ return;
+ }
+ LLGLEnable blend(GL_BLEND);
+ switch (vobj->getLastUpdateType())
+ {
+ case OUT_FULL:
+ glColor4f(0,1,0,0.5f);
+ break;
+ case OUT_TERSE_IMPROVED:
+ glColor4f(0,1,1,0.5f);
+ break;
+ case OUT_FULL_COMPRESSED:
+ if (vobj->getLastUpdateCached())
+ {
+ glColor4f(1,0,0,0.5f);
+ }
+ else
+ {
+ glColor4f(1,1,0,0.5f);
+ }
+ break;
+ case OUT_FULL_CACHED:
+ glColor4f(0,0,1,0.5f);
+ break;
+ default:
+ llwarns << "Unknown update_type " << vobj->getLastUpdateType() << llendl;
+ break;
+ };
+ S32 num_faces = drawablep->getNumFaces();
+ if (num_faces)
+ {
+ for (S32 i = 0; i < num_faces; ++i)
+ {
+ pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
+ }
+ }
+}
+
void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
{
@@ -3018,6 +3061,10 @@ public:
{
renderRaycast(drawable);
}
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_UPDATE_TYPE))
+ {
+ renderUpdateType(drawable);
+ }
LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(drawable->getVObj().get());
@@ -3180,6 +3227,7 @@ void LLSpatialPartition::renderDebug()
LLPipeline::RENDER_DEBUG_OCCLUSION |
LLPipeline::RENDER_DEBUG_LIGHTS |
LLPipeline::RENDER_DEBUG_BATCH_SIZE |
+ LLPipeline::RENDER_DEBUG_UPDATE_TYPE |
LLPipeline::RENDER_DEBUG_BBOXES |
LLPipeline::RENDER_DEBUG_POINTS |
LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY |
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 8cdc9843ab..0eac7d5e2a 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -139,6 +139,7 @@
#include "lltrans.h"
#include "llui.h"
#include "llurldispatcher.h"
+#include "llurlentry.h"
#include "llslurl.h"
#include "llurlhistory.h"
#include "llurlwhitelist.h"
@@ -2881,9 +2882,17 @@ bool process_login_success_response()
if(!text.empty()) gAgentID.set(text);
gDebugInfo["AgentID"] = text;
+ // Agent id needed for parcel info request in LLUrlEntryParcel
+ // to resolve parcel name.
+ LLUrlEntryParcel::setAgentID(gAgentID);
+
text = response["session_id"].asString();
if(!text.empty()) gAgentSessionID.set(text);
gDebugInfo["SessionID"] = text;
+
+ // Session id needed for parcel info request in LLUrlEntryParcel
+ // to resolve parcel name.
+ LLUrlEntryParcel::setSessionID(gAgentSessionID);
text = response["secure_session_id"].asString();
if(!text.empty()) gAgent.mSecureSessionID.set(text);
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index d3b6dcd86f..8a0d0a6623 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -54,6 +54,7 @@
#include "llfilepicker.h"
#include "llnotifications.h"
+#include "lldiriterator.h"
#include "llevent.h" // LLSimpleListener
#include "llnotificationsutil.h"
#include "lluuid.h"
@@ -1115,7 +1116,8 @@ void LLViewerMedia::clearAllCookies()
}
// the hard part: iterate over all user directories and delete the cookie file from each one
- while(gDirUtilp->getNextFileInDir(base_dir, "*_*", filename))
+ LLDirIterator dir_iter(base_dir, "*_*");
+ while (dir_iter.next(filename))
{
target = base_dir;
target += filename;
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 9e16bf2fbb..7cc04e0338 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -557,7 +557,7 @@ class LLAdvancedCheckConsole : public view_listener_t
new_value = get_visibility( (void*)gDebugView->mMemoryView );
}
#endif
-
+
return new_value;
}
};
@@ -906,6 +906,10 @@ U32 info_display_from_string(std::string info_display)
{
return LLPipeline::RENDER_DEBUG_BATCH_SIZE;
}
+ else if ("update type" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_UPDATE_TYPE;
+ }
else if ("texture anim" == info_display)
{
return LLPipeline::RENDER_DEBUG_TEXTURE_ANIM;
@@ -4197,9 +4201,9 @@ class LLObjectEnableReturn : public view_listener_t
{
virtual bool apply(LLViewerObject* obj)
{
- return (obj->isOverAgentOwnedLand() ||
- obj->isOverGroupOwnedLand() ||
- obj->permModify());
+ return
+ obj->permModify() ||
+ obj->isReturnable();
}
} func;
const bool firstonly = true;
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 1804fac1b3..48794c4c9d 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -234,7 +234,9 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
mState(0),
mMedia(NULL),
mClickAction(0),
- mAttachmentItemID(LLUUID::null)
+ mAttachmentItemID(LLUUID::null),
+ mLastUpdateType(OUT_UNKNOWN),
+ mLastUpdateCached(FALSE)
{
if (!is_global)
{
@@ -516,20 +518,23 @@ void LLViewerObject::setNameValueList(const std::string& name_value_list)
// This method returns true if the object is over land owned by the
// agent.
-BOOL LLViewerObject::isOverAgentOwnedLand() const
+bool LLViewerObject::isReturnable()
{
- return mRegionp
- && mRegionp->getParcelOverlay()
- && mRegionp->getParcelOverlay()->isOwnedSelf(getPositionRegion());
-}
+ if (isAttachment())
+ {
+ return false;
+ }
+ std::vector<LLBBox> boxes;
+ boxes.push_back(LLBBox(getPositionRegion(), getRotationRegion(), getScale() * -0.5f, getScale() * 0.5f).getAxisAligned());
+ for (child_list_t::iterator iter = mChildList.begin();
+ iter != mChildList.end(); iter++)
+ {
+ LLViewerObject* child = *iter;
+ boxes.push_back(LLBBox(child->getPositionRegion(), child->getRotationRegion(), child->getScale() * -0.5f, child->getScale() * 0.5f).getAxisAligned());
+ }
-// This method returns true if the object is over land owned by the
-// agent.
-BOOL LLViewerObject::isOverGroupOwnedLand() const
-{
- return mRegionp
- && mRegionp->getParcelOverlay()
- && mRegionp->getParcelOverlay()->isOwnedGroup(getPositionRegion());
+ return mRegionp
+ && mRegionp->objectIsReturnable(getPositionRegion(), boxes);
}
BOOL LLViewerObject::setParent(LLViewerObject* parent)
@@ -5400,6 +5405,26 @@ void LLViewerObject::setAttachmentItemID(const LLUUID &id)
mAttachmentItemID = id;
}
+EObjectUpdateType LLViewerObject::getLastUpdateType() const
+{
+ return mLastUpdateType;
+}
+
+void LLViewerObject::setLastUpdateType(EObjectUpdateType last_update_type)
+{
+ mLastUpdateType = last_update_type;
+}
+
+BOOL LLViewerObject::getLastUpdateCached() const
+{
+ return mLastUpdateCached;
+}
+
+void LLViewerObject::setLastUpdateCached(BOOL last_update_cached)
+{
+ mLastUpdateCached = last_update_cached;
+}
+
const LLUUID &LLViewerObject::extractAttachmentItemID()
{
LLUUID item_id = LLUUID::null;
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index fe670f8827..614a5e59fa 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -77,6 +77,7 @@ typedef enum e_object_update_type
OUT_TERSE_IMPROVED,
OUT_FULL_COMPRESSED,
OUT_FULL_CACHED,
+ OUT_UNKNOWN,
} EObjectUpdateType;
@@ -226,12 +227,9 @@ public:
virtual BOOL hasLightTexture() const { return FALSE; }
// This method returns true if the object is over land owned by
- // the agent.
- BOOL isOverAgentOwnedLand() const;
-
- // True if over land owned by group of which the agent is
- // either officer or member.
- BOOL isOverGroupOwnedLand() const;
+ // the agent, one of its groups, or it encroaches and
+ // anti-encroachment is enabled
+ bool isReturnable();
/*
// This method will scan through this object, and then query the
@@ -696,8 +694,15 @@ public:
const LLUUID &getAttachmentItemID() const;
void setAttachmentItemID(const LLUUID &id);
const LLUUID &extractAttachmentItemID(); // find&set the inventory item ID of the attached object
+ EObjectUpdateType getLastUpdateType() const;
+ void setLastUpdateType(EObjectUpdateType last_update_type);
+ BOOL getLastUpdateCached() const;
+ void setLastUpdateCached(BOOL last_update_cached);
+
private:
LLUUID mAttachmentItemID; // ItemID of the associated object is in user inventory.
+ EObjectUpdateType mLastUpdateType;
+ BOOL mLastUpdateCached;
};
///////////////////
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index f5a32438cf..5849ab4307 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -56,6 +56,7 @@
#include "llresmgr.h"
#include "llviewerregion.h"
#include "llviewerstats.h"
+#include "llviewerstatsrecorder.h"
#include "llvoavatarself.h"
#include "lltoolmgr.h"
#include "lltoolpie.h"
@@ -302,8 +303,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
// have to transform to absolute coordinates.
num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData);
+ // I don't think this case is ever hit. TODO* Test this.
if (!cached && !compressed && update_type != OUT_FULL)
{
+ //llinfos << "TEST: !cached && !compressed && update_type != OUT_FULL" << llendl;
gTerseObjectUpdates += num_objects;
S32 size;
if (mesgsys->getReceiveCompressedSize())
@@ -314,7 +317,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
{
size = mesgsys->getReceiveSize();
}
- // llinfos << "Received terse " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << llendl;
+ //llinfos << "Received terse " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << llendl;
}
else
{
@@ -345,9 +348,14 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
U8 compressed_dpbuffer[2048];
LLDataPackerBinaryBuffer compressed_dp(compressed_dpbuffer, 2048);
LLDataPacker *cached_dpp = NULL;
-
+
+#if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(regionp);
+#endif
+
for (i = 0; i < num_objects; i++)
{
+ // timer is unused?
LLTimer update_timer;
BOOL justCreated = FALSE;
@@ -359,9 +367,11 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, i);
// Lookup data packer and add this id to cache miss lists if necessary.
- cached_dpp = regionp->getDP(id, crc);
+ U8 cache_miss_type = LLViewerRegion::CACHE_MISS_TYPE_NONE;
+ cached_dpp = regionp->getDP(id, crc, cache_miss_type);
if (cached_dpp)
{
+ // Cache Hit.
cached_dpp->reset();
cached_dpp->unpackUUID(fullid, "ID");
cached_dpp->unpackU32(local_id, "LocalID");
@@ -369,6 +379,11 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
}
else
{
+ // Cache Miss.
+ #if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::instance()->recordCacheMissEvent(id, update_type, cache_miss_type);
+ #endif
+
continue; // no data packer, skip this object
}
}
@@ -380,13 +395,15 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
compressed_dp.reset();
U32 flags = 0;
- if (update_type != OUT_TERSE_IMPROVED)
+ if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?
{
mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i);
}
+ // I don't think we ever use this flag from the server. DK 2010/12/09
if (flags & FLAGS_ZLIB_COMPRESSED)
{
+ //llinfos << "TEST: flags & FLAGS_ZLIB_COMPRESSED" << llendl;
compressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data);
mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compbuffer, 0, i);
uncompressed_length = 2048;
@@ -402,7 +419,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
}
- if (update_type != OUT_TERSE_IMPROVED)
+ if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?
{
compressed_dp.unpackUUID(fullid, "ID");
compressed_dp.unpackU32(local_id, "LocalID");
@@ -422,7 +439,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
}
}
}
- else if (update_type != OUT_FULL)
+ else if (update_type != OUT_FULL) // !compressed, !OUT_FULL ==> OUT_FULL_CACHED only?
{
mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i);
getUUIDFromLocal(fullid,
@@ -435,7 +452,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
mNumUnknownUpdates++;
}
}
- else
+ else // OUT_FULL only?
{
mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_FullID, fullid, i);
mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i);
@@ -467,12 +484,12 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
gMessageSystem->getSenderPort());
if (objectp->mLocalID != local_id)
- { // Update local ID in object with the one sent from the region
+ { // Update local ID in object with the one sent from the region
objectp->mLocalID = local_id;
}
if (objectp->getRegion() != regionp)
- { // Object changed region, so update it
+ { // Object changed region, so update it
objectp->updateRegion(regionp); // for LLVOAvatar
}
}
@@ -483,18 +500,24 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
{
if (update_type == OUT_TERSE_IMPROVED)
{
- // llinfos << "terse update for an unknown object:" << fullid << llendl;
+ // llinfos << "terse update for an unknown object (compressed):" << fullid << llendl;
+ #if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
+ #endif
continue;
}
}
- else if (cached)
+ else if (cached) // Cache hit only?
{
}
else
{
if (update_type != OUT_FULL)
{
- // llinfos << "terse update for an unknown object:" << fullid << llendl;
+ //llinfos << "terse update for an unknown object:" << fullid << llendl;
+ #if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
+ #endif
continue;
}
@@ -504,7 +527,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
if (mDeadObjects.find(fullid) != mDeadObjects.end())
{
mNumDeadObjectUpdates++;
- // llinfos << "update for a dead object:" << fullid << llendl;
+ //llinfos << "update for a dead object:" << fullid << llendl;
+ #if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
+ #endif
continue;
}
#endif
@@ -512,6 +538,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
objectp = createObject(pcode, regionp, fullid, local_id, gMessageSystem->getSender());
if (!objectp)
{
+ llinfos << "createObject failure for object: " << fullid << llendl;
+ #if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
+ #endif
continue;
}
justCreated = TRUE;
@@ -524,19 +554,26 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
llwarns << "Dead object " << objectp->mID << " in UUID map 1!" << llendl;
}
+ bool bCached = false;
if (compressed)
{
- if (update_type != OUT_TERSE_IMPROVED)
+ if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?
{
objectp->mLocalID = local_id;
}
processUpdateCore(objectp, user_data, i, update_type, &compressed_dp, justCreated);
- if (update_type != OUT_TERSE_IMPROVED)
+ if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?
{
+ bCached = true;
+ #if LL_RECORD_VIEWER_STATS
+ LLViewerRegion::eCacheUpdateResult result = objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp);
+ LLViewerStatsRecorder::instance()->recordCacheFullUpdate(local_id, update_type, result, objectp);
+ #else
objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp);
+ #endif
}
}
- else if (cached)
+ else if (cached) // Cache hit only?
{
objectp->mLocalID = local_id;
processUpdateCore(objectp, user_data, i, update_type, cached_dpp, justCreated);
@@ -549,8 +586,17 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
}
processUpdateCore(objectp, user_data, i, update_type, NULL, justCreated);
}
+ #if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::instance()->recordObjectUpdateEvent(local_id, update_type, objectp);
+ #endif
+ objectp->setLastUpdateType(update_type);
+ objectp->setLastUpdateCached(bCached);
}
+#if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::instance()->endObjectUpdateEvents();
+#endif
+
LLVOAvatar::cullAvatarsByPixelArea();
}
@@ -681,12 +727,12 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
// update global timer
F32 last_time = gFrameTimeSeconds;
- U64 time = totalTime(); // this will become the new gFrameTime when the update is done
+ U64 time = totalTime(); // this will become the new gFrameTime when the update is done
// Time _can_ go backwards, for example if the user changes the system clock.
// It doesn't cause any fatal problems (just some oddness with stats), so we shouldn't assert here.
// llassert(time > gFrameTime);
F64 time_diff = U64_to_F64(time - gFrameTime)/(F64)SEC_TO_MICROSEC;
- gFrameTime = time;
+ gFrameTime = time;
F64 time_since_start = U64_to_F64(gFrameTime - gStartTime)/(F64)SEC_TO_MICROSEC;
gFrameTimeSeconds = (F32)time_since_start;
@@ -788,7 +834,7 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
{
std::string id_str;
objectp->mID.toString(id_str);
- std::string tmpstr = std::string("Par: ") + id_str;
+ std::string tmpstr = std::string("Par: ") + id_str;
addDebugBeacon(objectp->getPositionAgent(),
tmpstr,
LLColor4(1.f,0.f,0.f,1.f),
@@ -808,12 +854,12 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
std::string tmpstr;
if (objectp->getParent())
{
- tmpstr = std::string("ChP: ") + id_str;
+ tmpstr = std::string("ChP: ") + id_str;
text_color = LLColor4(0.f, 1.f, 0.f, 1.f);
}
else
{
- tmpstr = std::string("ChNoP: ") + id_str;
+ tmpstr = std::string("ChNoP: ") + id_str;
text_color = LLColor4(1.f, 0.f, 0.f, 1.f);
}
id = sIndexAndLocalIDToUUID[oi.mParentInfo];
@@ -1519,8 +1565,8 @@ void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port)
llinfos << "Agent: " << objectp->getPositionAgent() << llendl;
addDebugBeacon(objectp->getPositionAgent(),"");
#endif
- gPipeline.markMoved(objectp->mDrawable);
- objectp->setChanged(LLXform::MOVED | LLXform::SILHOUETTE);
+ gPipeline.markMoved(objectp->mDrawable);
+ objectp->setChanged(LLXform::MOVED | LLXform::SILHOUETTE);
// Flag the object as no longer orphaned
childp->mOrphaned = FALSE;
diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp
index eee653b0c1..d07e06f6a7 100644
--- a/indra/newview/llviewerparceloverlay.cpp
+++ b/indra/newview/llviewerparceloverlay.cpp
@@ -145,6 +145,35 @@ BOOL LLViewerParcelOverlay::isOwnedOther(const LLVector3& pos) const
return (PARCEL_OWNED == overlay || PARCEL_FOR_SALE == overlay);
}
+bool LLViewerParcelOverlay::encroachesOwned(const std::vector<LLBBox>& boxes) const
+{
+ // boxes are expected to already be axis aligned
+ for (U32 i = 0; i < boxes.size(); ++i)
+ {
+ LLVector3 min = boxes[i].getMinAgent();
+ LLVector3 max = boxes[i].getMaxAgent();
+
+ S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
+ S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
+ S32 top = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
+ S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
+
+ for (S32 row = top; row <= bottom; row++)
+ {
+ for (S32 column = left; column <= right; column++)
+ {
+ U8 type = ownership(row, column);
+ if ((PARCEL_SELF == type)
+ || (PARCEL_GROUP == type))
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
BOOL LLViewerParcelOverlay::isSoundLocal(const LLVector3& pos) const
{
S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h
index 61be220312..c80baedda6 100644
--- a/indra/newview/llviewerparceloverlay.h
+++ b/indra/newview/llviewerparceloverlay.h
@@ -30,6 +30,7 @@
// The ownership data for land parcels.
// One of these structures per region.
+#include "llbbox.h"
#include "lldarray.h"
#include "llframetimer.h"
#include "lluuid.h"
@@ -54,6 +55,12 @@ public:
BOOL isOwnedSelf(const LLVector3& pos) const;
BOOL isOwnedGroup(const LLVector3& pos) const;
BOOL isOwnedOther(const LLVector3& pos) const;
+
+ // "encroaches" means the prim hangs over the parcel, but its center
+ // might be in another parcel. for now, we simply test axis aligned
+ // bounding boxes which isn't perfect, but is close
+ bool encroachesOwned(const std::vector<LLBBox>& boxes) const;
+
BOOL isSoundLocal(const LLVector3& pos) const;
BOOL isBuildCameraAllowed(const LLVector3& pos) const;
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 551ba18dd5..3b2cfe656f 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -59,6 +59,7 @@
#include "llurldispatcher.h"
#include "llviewerobjectlist.h"
#include "llviewerparceloverlay.h"
+#include "llviewerstatsrecorder.h"
#include "llvlmanager.h"
#include "llvlcomposition.h"
#include "llvocache.h"
@@ -1032,7 +1033,7 @@ void LLViewerRegion::getInfo(LLSD& info)
info["Region"]["Handle"]["y"] = (LLSD::Integer)y;
}
-void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp)
+LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp)
{
U32 local_id = objectp->getLocalID();
U32 crc = objectp->getCRC();
@@ -1046,35 +1047,36 @@ void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinary
{
// Record a hit
entry->recordDupe();
+ return CACHE_UPDATE_DUPE;
}
- else
- {
- // Update the cache entry
- mCacheMap.erase(local_id);
- delete entry;
- entry = new LLVOCacheEntry(local_id, crc, dp);
- mCacheMap[local_id] = entry;
- }
- }
- else
- {
- // we haven't seen this object before
- // Create new entry and add to map
- if (mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES)
- {
- mCacheMap.erase(mCacheMap.begin());
- }
+ // Update the cache entry
+ mCacheMap.erase(local_id);
+ delete entry;
entry = new LLVOCacheEntry(local_id, crc, dp);
-
mCacheMap[local_id] = entry;
+ return CACHE_UPDATE_CHANGED;
}
- return ;
+
+ // we haven't seen this object before
+
+ // Create new entry and add to map
+ eCacheUpdateResult result = CACHE_UPDATE_ADDED;
+ if (mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES)
+ {
+ mCacheMap.erase(mCacheMap.begin());
+ result = CACHE_UPDATE_REPLACED;
+
+ }
+ entry = new LLVOCacheEntry(local_id, crc, dp);
+
+ mCacheMap[local_id] = entry;
+ return result;
}
// Get data packer for this object, if we have cached data
// AND the CRC matches. JC
-LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc)
+LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type)
{
llassert(mCacheLoaded);
@@ -1087,17 +1089,20 @@ LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc)
{
// Record a hit
entry->recordHit();
+ cache_miss_type = CACHE_MISS_TYPE_NONE;
return entry->getDP(crc);
}
else
{
// llinfos << "CRC miss for " << local_id << llendl;
+ cache_miss_type = CACHE_MISS_TYPE_CRC;
mCacheMissCRC.put(local_id);
}
}
else
{
// llinfos << "Cache miss for " << local_id << llendl;
+ cache_miss_type = CACHE_MISS_TYPE_FULL;
mCacheMissFull.put(local_id);
}
return NULL;
@@ -1119,9 +1124,6 @@ void LLViewerRegion::requestCacheMisses()
S32 blocks = 0;
S32 i;
- const U8 CACHE_MISS_TYPE_FULL = 0;
- const U8 CACHE_MISS_TYPE_CRC = 1;
-
// Send full cache miss updates. For these, we KNOW we don't
// have a viewer object.
for (i = 0; i < full_count; i++)
@@ -1184,6 +1186,11 @@ void LLViewerRegion::requestCacheMisses()
mCacheDirty = TRUE ;
// llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl;
+ #if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(this);
+ LLViewerStatsRecorder::instance()->recordRequestCacheMissesEvent(full_count + crc_count);
+ LLViewerStatsRecorder::instance()->endObjectUpdateEvents();
+ #endif
}
void LLViewerRegion::dumpCache()
@@ -1400,7 +1407,6 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
capabilityNames.append("SendUserReportWithScreenshot");
capabilityNames.append("ServerReleaseNotes");
capabilityNames.append("SetDisplayName");
- capabilityNames.append("SimConsole");
capabilityNames.append("SimConsoleAsync");
capabilityNames.append("StartGroupProposal");
capabilityNames.append("TextureStats");
@@ -1497,6 +1503,20 @@ LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type)
return NULL;
}
+// the viewer can not yet distinquish between normal- and estate-owned objects
+// so we collapse these two bits and enable the UI if either are set
+const U32 ALLOW_RETURN_ENCROACHING_OBJECT = REGION_FLAGS_ALLOW_RETURN_ENCROACHING_OBJECT
+ | REGION_FLAGS_ALLOW_RETURN_ENCROACHING_ESTATE_OBJECT;
+
+bool LLViewerRegion::objectIsReturnable(const LLVector3& pos, const std::vector<LLBBox>& boxes) const
+{
+ return (mParcelOverlay != NULL)
+ && (mParcelOverlay->isOwnedSelf(pos)
+ || mParcelOverlay->isOwnedGroup(pos)
+ || ((mRegionFlags & ALLOW_RETURN_ENCROACHING_OBJECT)
+ && mParcelOverlay->encroachesOwned(boxes)) );
+}
+
void LLViewerRegion::showReleaseNotes()
{
std::string url = this->getCapability("ServerReleaseNotes");
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 8b71998f60..7c6559203e 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -33,6 +33,7 @@
#include "lldarray.h"
#include "llwind.h"
+#include "llbbox.h"
#include "llcloud.h"
#include "llstat.h"
#include "v3dmath.h"
@@ -50,7 +51,7 @@
// Surface id's
#define LAND 1
#define WATER 2
-const U32 MAX_OBJECT_CACHE_ENTRIES = 10000;
+const U32 MAX_OBJECT_CACHE_ENTRIES = 50000;
class LLEventPoll;
@@ -274,9 +275,24 @@ public:
void getInfo(LLSD& info);
+ typedef enum
+ {
+ CACHE_MISS_TYPE_FULL = 0,
+ CACHE_MISS_TYPE_CRC,
+ CACHE_MISS_TYPE_NONE
+ } eCacheMissType;
+
+ typedef enum
+ {
+ CACHE_UPDATE_DUPE = 0,
+ CACHE_UPDATE_CHANGED,
+ CACHE_UPDATE_ADDED,
+ CACHE_UPDATE_REPLACED
+ } eCacheUpdateResult;
+
// handle a full update message
- void cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp);
- LLDataPacker *getDP(U32 local_id, U32 crc);
+ eCacheUpdateResult cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp);
+ LLDataPacker *getDP(U32 local_id, U32 crc, U8 &cache_miss_type);
void requestCacheMisses();
void addCacheMissFull(const U32 local_id);
@@ -293,6 +309,8 @@ public:
std::string getHttpUrl() const { return mHttpUrl ;}
LLSpatialPartition* getSpatialPartition(U32 type);
+
+ bool objectIsReturnable(const LLVector3& pos, const std::vector<LLBBox>& boxes) const;
public:
struct CompareDistance
{
diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp
new file mode 100644
index 0000000000..e9d21b4848
--- /dev/null
+++ b/indra/newview/llviewerstatsrecorder.cpp
@@ -0,0 +1,258 @@
+/**
+ * @file llviewerstatsrecorder.cpp
+ * @brief record info about viewer events to a metrics log file
+ *
+ * $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 "llviewerprecompiledheaders.h"
+#include "llviewerstatsrecorder.h"
+
+#if LL_RECORD_VIEWER_STATS
+
+#include "llfile.h"
+#include "llviewerregion.h"
+#include "llviewerobject.h"
+
+
+// To do - something using region name or global position
+#if LL_WINDOWS
+ static const std::string STATS_FILE_NAME("C:\\ViewerObjectCacheStats.csv");
+#else
+ static const std::string STATS_FILE_NAME("/tmp/viewerstats.csv");
+#endif
+
+LLViewerStatsRecorder* LLViewerStatsRecorder::sInstance = NULL;
+LLViewerStatsRecorder::LLViewerStatsRecorder() :
+ mObjectCacheFile(NULL),
+ mTimer(),
+ mRegionp(NULL),
+ mStartTime(0.f),
+ mProcessingTime(0.f)
+{
+ if (NULL != sInstance)
+ {
+ llerrs << "Attempted to create multiple instances of LLViewerStatsRecorder!" << llendl;
+ }
+ sInstance = this;
+ clearStats();
+}
+
+LLViewerStatsRecorder::~LLViewerStatsRecorder()
+{
+ if (mObjectCacheFile != NULL)
+ {
+ LLFile::close(mObjectCacheFile);
+ mObjectCacheFile = NULL;
+ }
+}
+
+// static
+void LLViewerStatsRecorder::initClass()
+{
+ sInstance = new LLViewerStatsRecorder();
+}
+
+// static
+void LLViewerStatsRecorder::cleanupClass()
+{
+ delete sInstance;
+ sInstance = NULL;
+}
+
+
+void LLViewerStatsRecorder::initStatsRecorder(LLViewerRegion *regionp)
+{
+ if (mObjectCacheFile == NULL)
+ {
+ mStartTime = LLTimer::getTotalTime();
+ mObjectCacheFile = LLFile::fopen(STATS_FILE_NAME, "wb");
+ if (mObjectCacheFile)
+ { // Write column headers
+ std::ostringstream data_msg;
+ data_msg << "EventTime, "
+ << "ProcessingTime, "
+ << "CacheHits, "
+ << "CacheFullMisses, "
+ << "CacheCrcMisses, "
+ << "FullUpdates, "
+ << "TerseUpdates, "
+ << "CacheMissRequests, "
+ << "CacheMissResponses, "
+ << "CacheUpdateDupes, "
+ << "CacheUpdateChanges, "
+ << "CacheUpdateAdds, "
+ << "CacheUpdateReplacements, "
+ << "UpdateFailures"
+ << "\n";
+
+ fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile );
+ }
+ }
+}
+
+void LLViewerStatsRecorder::beginObjectUpdateEvents(LLViewerRegion *regionp)
+{
+ initStatsRecorder(regionp);
+ mRegionp = regionp;
+ mProcessingTime = LLTimer::getTotalTime();
+ clearStats();
+}
+
+void LLViewerStatsRecorder::clearStats()
+{
+ mObjectCacheHitCount = 0;
+ mObjectCacheMissFullCount = 0;
+ mObjectCacheMissCrcCount = 0;
+ mObjectFullUpdates = 0;
+ mObjectTerseUpdates = 0;
+ mObjectCacheMissRequests = 0;
+ mObjectCacheMissResponses = 0;
+ mObjectCacheUpdateDupes = 0;
+ mObjectCacheUpdateChanges = 0;
+ mObjectCacheUpdateAdds = 0;
+ mObjectCacheUpdateReplacements = 0;
+ mObjectUpdateFailures = 0;
+}
+
+
+void LLViewerStatsRecorder::recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type)
+{
+ mObjectUpdateFailures++;
+}
+
+void LLViewerStatsRecorder::recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type)
+{
+ if (LLViewerRegion::CACHE_MISS_TYPE_FULL == cache_miss_type)
+ {
+ mObjectCacheMissFullCount++;
+ }
+ else
+ {
+ mObjectCacheMissCrcCount++;
+ }
+}
+
+void LLViewerStatsRecorder::recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp)
+{
+ switch (update_type)
+ {
+ case OUT_FULL:
+ mObjectFullUpdates++;
+ break;
+ case OUT_TERSE_IMPROVED:
+ mObjectTerseUpdates++;
+ break;
+ case OUT_FULL_COMPRESSED:
+ mObjectCacheMissResponses++;
+ break;
+ case OUT_FULL_CACHED:
+ mObjectCacheHitCount++;
+ break;
+ default:
+ llwarns << "Unknown update_type" << llendl;
+ break;
+ };
+}
+
+void LLViewerStatsRecorder::recordCacheFullUpdate(U32 local_id, const EObjectUpdateType update_type, LLViewerRegion::eCacheUpdateResult update_result, LLViewerObject* objectp)
+{
+ switch (update_result)
+ {
+ case LLViewerRegion::CACHE_UPDATE_DUPE:
+ mObjectCacheUpdateDupes++;
+ break;
+ case LLViewerRegion::CACHE_UPDATE_CHANGED:
+ mObjectCacheUpdateChanges++;
+ break;
+ case LLViewerRegion::CACHE_UPDATE_ADDED:
+ mObjectCacheUpdateAdds++;
+ break;
+ case LLViewerRegion::CACHE_UPDATE_REPLACED:
+ mObjectCacheUpdateReplacements++;
+ break;
+ default:
+ llwarns << "Unknown update_result type" << llendl;
+ break;
+ };
+}
+
+void LLViewerStatsRecorder::recordRequestCacheMissesEvent(S32 count)
+{
+ mObjectCacheMissRequests += count;
+}
+
+void LLViewerStatsRecorder::endObjectUpdateEvents()
+{
+ llinfos << "ILX: "
+ << mObjectCacheHitCount << " hits, "
+ << mObjectCacheMissFullCount << " full misses, "
+ << mObjectCacheMissCrcCount << " crc misses, "
+ << mObjectFullUpdates << " full updates, "
+ << mObjectTerseUpdates << " terse updates, "
+ << mObjectCacheMissRequests << " cache miss requests, "
+ << mObjectCacheMissResponses << " cache miss responses, "
+ << mObjectCacheUpdateDupes << " cache update dupes, "
+ << mObjectCacheUpdateChanges << " cache update changes, "
+ << mObjectCacheUpdateAdds << " cache update adds, "
+ << mObjectCacheUpdateReplacements << " cache update replacements, "
+ << mObjectUpdateFailures << " update failures"
+ << llendl;
+
+ S32 total_objects = mObjectCacheHitCount + mObjectCacheMissCrcCount + mObjectCacheMissFullCount + mObjectFullUpdates + mObjectTerseUpdates + mObjectCacheMissRequests + mObjectCacheMissResponses + mObjectCacheUpdateDupes + mObjectCacheUpdateChanges + mObjectCacheUpdateAdds + mObjectCacheUpdateReplacements + mObjectUpdateFailures;
+ if (mObjectCacheFile != NULL &&
+ total_objects > 0)
+ {
+ std::ostringstream data_msg;
+ F32 processing32 = (F32) ((LLTimer::getTotalTime() - mProcessingTime) / 1000.0);
+
+ data_msg << getTimeSinceStart()
+ << ", " << processing32
+ << ", " << mObjectCacheHitCount
+ << ", " << mObjectCacheMissFullCount
+ << ", " << mObjectCacheMissCrcCount
+ << ", " << mObjectFullUpdates
+ << ", " << mObjectTerseUpdates
+ << ", " << mObjectCacheMissRequests
+ << ", " << mObjectCacheMissResponses
+ << ", " << mObjectCacheUpdateDupes
+ << ", " << mObjectCacheUpdateChanges
+ << ", " << mObjectCacheUpdateAdds
+ << ", " << mObjectCacheUpdateReplacements
+ << ", " << mObjectUpdateFailures
+ << "\n";
+
+ fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile );
+ }
+
+ clearStats();
+}
+
+F32 LLViewerStatsRecorder::getTimeSinceStart()
+{
+ return (F32) ((LLTimer::getTotalTime() - mStartTime) / 1000.0);
+}
+
+#endif
+
+
+
diff --git a/indra/newview/llviewerstatsrecorder.h b/indra/newview/llviewerstatsrecorder.h
new file mode 100644
index 0000000000..612ac380f7
--- /dev/null
+++ b/indra/newview/llviewerstatsrecorder.h
@@ -0,0 +1,97 @@
+/**
+ * @file llviewerstatsrecorder.h
+ * @brief record info about viewer events to a metrics log file
+ *
+ * $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 LLVIEWERSTATSRECORDER_H
+#define LLVIEWERSTATSRECORDER_H
+
+
+// This is a diagnostic class used to record information from the viewer
+// for analysis.
+
+// This is normally 0. Set to 1 to enable viewer stats recording
+#define LL_RECORD_VIEWER_STATS 0
+
+
+#if LL_RECORD_VIEWER_STATS
+#include "llframetimer.h"
+#include "llviewerobject.h"
+#include "llviewerregion.h"
+
+class LLMutex;
+class LLViewerRegion;
+class LLViewerObject;
+
+class LLViewerStatsRecorder
+{
+ public:
+ LLViewerStatsRecorder();
+ ~LLViewerStatsRecorder();
+
+ static void initClass();
+ static void cleanupClass();
+ static LLViewerStatsRecorder* instance() {return sInstance; }
+
+ void initStatsRecorder(LLViewerRegion *regionp);
+
+ void beginObjectUpdateEvents(LLViewerRegion *regionp);
+ void recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type);
+ void recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type);
+ void recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp);
+ void recordCacheFullUpdate(U32 local_id, const EObjectUpdateType update_type, LLViewerRegion::eCacheUpdateResult update_result, LLViewerObject* objectp);
+ void recordRequestCacheMissesEvent(S32 count);
+ void endObjectUpdateEvents();
+
+ F32 getTimeSinceStart();
+
+private:
+ static LLViewerStatsRecorder* sInstance;
+
+ LLFILE * mObjectCacheFile; // File to write data into
+ LLFrameTimer mTimer;
+ LLViewerRegion* mRegionp;
+ F64 mStartTime;
+ F64 mProcessingTime;
+
+ S32 mObjectCacheHitCount;
+ S32 mObjectCacheMissFullCount;
+ S32 mObjectCacheMissCrcCount;
+ S32 mObjectFullUpdates;
+ S32 mObjectTerseUpdates;
+ S32 mObjectCacheMissRequests;
+ S32 mObjectCacheMissResponses;
+ S32 mObjectCacheUpdateDupes;
+ S32 mObjectCacheUpdateChanges;
+ S32 mObjectCacheUpdateAdds;
+ S32 mObjectCacheUpdateReplacements;
+ S32 mObjectUpdateFailures;
+
+
+ void clearStats();
+};
+#endif // LL_RECORD_VIEWER_STATS
+
+#endif // LLVIEWERSTATSRECORDER_H
+
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index bb4c5b1804..fd89044995 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -2106,31 +2106,6 @@ void LLVOAvatar::computeBodySize()
gAgent.sendAgentSetAppearance();
}
}
-
-/* debug spam
- std::cout << "skull = " << skull << std::endl; // adebug
- std::cout << "head = " << head << std::endl; // adebug
- std::cout << "head_scale = " << head_scale << std::endl; // adebug
- std::cout << "neck = " << neck << std::endl; // adebug
- std::cout << "neck_scale = " << neck_scale << std::endl; // adebug
- std::cout << "chest = " << chest << std::endl; // adebug
- std::cout << "chest_scale = " << chest_scale << std::endl; // adebug
- std::cout << "torso = " << torso << std::endl; // adebug
- std::cout << "torso_scale = " << torso_scale << std::endl; // adebug
- std::cout << std::endl; // adebug
-
- std::cout << "pelvis_scale = " << pelvis_scale << std::endl;// adebug
- std::cout << std::endl; // adebug
-
- std::cout << "hip = " << hip << std::endl; // adebug
- std::cout << "hip_scale = " << hip_scale << std::endl; // adebug
- std::cout << "ankle = " << ankle << std::endl; // adebug
- std::cout << "ankle_scale = " << ankle_scale << std::endl; // adebug
- std::cout << "foot = " << foot << std::endl; // adebug
- std::cout << "mBodySize = " << mBodySize << std::endl; // adebug
- std::cout << "mPelvisToFoot = " << mPelvisToFoot << std::endl; // adebug
- std::cout << std::endl; // adebug
-*/
}
//------------------------------------------------------------------------
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 145ee31260..c26008d640 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -40,6 +40,7 @@ BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes)
return apr_file->write(src, n_bytes) == n_bytes ;
}
+
//---------------------------------------------------------------------------
// LLVOCacheEntry
//---------------------------------------------------------------------------
@@ -212,8 +213,8 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const
if(success)
{
success = check_write(apr_file, (void*)mBuffer, size);
+ }
}
-}
return success ;
}
@@ -224,7 +225,8 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const
// Format string used to construct filename for the object cache
static const char OBJECT_CACHE_FILENAME[] = "objects_%d_%d.slc";
-const U32 NUM_ENTRIES_TO_PURGE = 16 ;
+// Throw out 1/20 (5%) of our cache entries if we run out of room.
+const U32 ENTRIES_PURGE_FACTOR = 20;
const char* object_cache_dirname = "objectcache";
const char* header_filename = "object.cache";
@@ -259,7 +261,6 @@ void LLVOCache::destroyClass()
LLVOCache::LLVOCache():
mInitialized(FALSE),
mReadOnly(TRUE),
- mNumEntries(0),
mCacheSize(1)
{
mEnabled = gSavedSettings.getBOOL("ObjectCacheEnabled");
@@ -286,8 +287,15 @@ void LLVOCache::setDirNames(ELLPath location)
void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version)
{
- if(mInitialized || !mEnabled)
+ if(!mEnabled)
{
+ llwarns << "Not initializing cache: Cache is currently disabled." << llendl;
+ return ;
+ }
+
+ if(mInitialized)
+ {
+ llwarns << "Cache already initialized." << llendl;
return ;
}
@@ -299,7 +307,6 @@ void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version)
mCacheSize = size;
- mMetaInfo.mVersion = cache_version;
readCacheHeader();
mInitialized = TRUE ;
@@ -321,12 +328,14 @@ void LLVOCache::removeCache(ELLPath location)
{
if(mReadOnly)
{
+ llwarns << "Not removing cache at " << location << ": Cache is currently in read-only mode." << llendl;
return ;
}
std::string delem = gDirUtilp->getDirDelimiter();
std::string mask = delem + "*";
std::string cache_dir = gDirUtilp->getExpandedFilename(location, object_cache_dirname);
+ llinfos << "Removing cache at " << cache_dir << llendl;
gDirUtilp->deleteFilesInDir(cache_dir, mask); //delete all files
LLFile::rmdir(cache_dir);
@@ -339,11 +348,13 @@ void LLVOCache::removeCache()
llassert_always(mInitialized) ;
if(mReadOnly)
{
+ llwarns << "Not clearing object cache: Cache is currently in read-only mode." << llendl;
return ;
}
std::string delem = gDirUtilp->getDirDelimiter();
std::string mask = delem + "*";
+ llinfos << "Removing cache at " << mObjectCacheDirName << llendl;
gDirUtilp->deleteFilesInDir(mObjectCacheDirName, mask);
clearCacheInMemory() ;
@@ -352,16 +363,8 @@ void LLVOCache::removeCache()
void LLVOCache::clearCacheInMemory()
{
- if(!mHeaderEntryQueue.empty())
- {
- for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin(); iter != mHeaderEntryQueue.end(); ++iter)
- {
- delete *iter ;
- }
- mHeaderEntryQueue.clear();
- mHandleEntryMap.clear();
- mNumEntries = 0 ;
- }
+ std::for_each(mHandleEntryMap.begin(), mHandleEntryMap.end(), DeletePairedPointer());
+ mHandleEntryMap.clear();
}
void LLVOCache::getObjectCacheFilename(U64 handle, std::string& filename)
@@ -379,6 +382,7 @@ void LLVOCache::removeFromCache(U64 handle)
{
if(mReadOnly)
{
+ llwarns << "Not removing cache for handle " << handle << ": Cache is currently in read-only mode." << llendl;
return ;
}
@@ -387,24 +391,28 @@ void LLVOCache::removeFromCache(U64 handle)
LLAPRFile::remove(filename, mLocalAPRFilePoolp);
}
-BOOL LLVOCache::checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes)
+BOOL LLVOCache::checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error)
{
if(!check_read(apr_file, src, n_bytes))
{
- delete apr_file ;
- removeCache() ;
+ if (remove_cache_on_error)
+ {
+ removeCache() ;
+ }
return FALSE ;
}
return TRUE ;
}
-BOOL LLVOCache::checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes)
+BOOL LLVOCache::checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error)
{
if(!check_write(apr_file, src, n_bytes))
{
- delete apr_file ;
- removeCache() ;
+ if (remove_cache_on_error)
+ {
+ removeCache() ;
+ }
return FALSE ;
}
@@ -415,7 +423,8 @@ void LLVOCache::readCacheHeader()
{
if(!mEnabled)
{
- return ;
+ llwarns << "Not reading cache header: Cache is currently disabled." << llendl;
+ return;
}
//clear stale info.
@@ -423,33 +432,35 @@ void LLVOCache::readCacheHeader()
if (LLAPRFile::isExist(mHeaderFileName, mLocalAPRFilePoolp))
{
- LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_READ|APR_BINARY, mLocalAPRFilePoolp);
+ LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_FOPEN_READ|APR_FOPEN_BINARY, mLocalAPRFilePoolp);
//read the meta element
- if(!checkRead(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)))
+ bool remove_cache_on_error = false;
+ if(!checkRead(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo), remove_cache_on_error))
{
- return ;
+ llwarns << "Error reading meta information from cache header." << llendl;
+ delete apr_file;
+ return;
}
HeaderEntryInfo* entry ;
- mNumEntries = 0 ;
- while(mNumEntries < mCacheSize)
+ for(U32 entry_index = 0; entry_index < mCacheSize; ++entry_index)
{
entry = new HeaderEntryInfo() ;
- if(!checkRead(apr_file, entry, sizeof(HeaderEntryInfo)))
+ if(!checkRead(apr_file, entry, sizeof(HeaderEntryInfo), remove_cache_on_error))
{
+ llwarns << "Error reading cache header entry. (entry_index=" << entry_index << ")" << llendl;
delete entry ;
- return ;
+ break;
}
else if(!entry->mTime) //end of the cache.
{
delete entry ;
- return ;
+ break;
}
- entry->mIndex = mNumEntries++ ;
- mHeaderEntryQueue.insert(entry) ;
- mHandleEntryMap[entry->mHandle] = entry ;
+ entry->mIndex = entry_index;
+ mHandleEntryMap[entry->mHandle] = entry;
}
delete apr_file ;
@@ -462,40 +473,57 @@ void LLVOCache::readCacheHeader()
void LLVOCache::writeCacheHeader()
{
- if(mReadOnly || !mEnabled)
+ if (!mEnabled)
{
- return ;
- }
+ llwarns << "Not writing cache header: Cache is currently disabled." << llendl;
+ return;
+ }
+
+ if(mReadOnly)
+ {
+ llwarns << "Not writing cache header: Cache is currently in read-only mode." << llendl;
+ return;
+ }
- LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
+ LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_FOPEN_CREATE|APR_FOPEN_WRITE|APR_FOPEN_BINARY|APR_FOPEN_TRUNCATE, mLocalAPRFilePoolp);
//write the meta element
if(!checkWrite(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)))
{
- return ;
+ llwarns << "Error writing meta information to cache header." << llendl;
+ delete apr_file;
+ return;
}
- mNumEntries = 0 ;
- for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; iter != mHeaderEntryQueue.end(); ++iter)
+ U32 entry_index = 0;
+ handle_entry_map_t::iterator iter_end = mHandleEntryMap.end();
+ for(handle_entry_map_t::iterator iter = mHandleEntryMap.begin();
+ iter != iter_end;
+ ++iter)
{
- (*iter)->mIndex = mNumEntries++ ;
- if(!checkWrite(apr_file, (void*)*iter, sizeof(HeaderEntryInfo)))
+ HeaderEntryInfo* entry = iter->second;
+ entry->mIndex = entry_index++;
+ if(!checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)))
{
- return ;
+ llwarns << "Failed to write cache header for entry " << entry->mHandle << " (entry_index = " << entry_index << ")" << llendl;
+ delete apr_file;
+ return;
}
}
- mNumEntries = mHeaderEntryQueue.size() ;
- if(mNumEntries < mCacheSize)
+ // Why do we need to fill the cache header with default entries? DK 2010-12-14
+ // It looks like we currently rely on the file being pre-allocated so we can seek during updateEntry().
+ if(entry_index < mCacheSize)
{
HeaderEntryInfo* entry = new HeaderEntryInfo() ;
- for(U32 i = mNumEntries ; i < mCacheSize; i++)
+ for(; entry_index < mCacheSize; ++entry_index)
{
//fill the cache with the default entry.
if(!checkWrite(apr_file, entry, sizeof(HeaderEntryInfo)))
{
+ llwarns << "Failed to fill cache header with default entries (entry_index = " << entry_index << "). Switching to read-only mode." << llendl;
mReadOnly = TRUE ; //disable the cache.
- return ;
+ break;
}
}
delete entry ;
@@ -505,16 +533,19 @@ void LLVOCache::writeCacheHeader()
BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry)
{
- LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
+ LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_FOPEN_WRITE|APR_FOPEN_BINARY, mLocalAPRFilePoolp);
apr_file->seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ;
- return checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ;
+ BOOL result = checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ;
+ delete apr_file;
+ return result;
}
void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map)
{
if(!mEnabled)
{
+ llwarns << "Not reading cache for handle " << handle << "): Cache is currently disabled." << llendl;
return ;
}
llassert_always(mInitialized);
@@ -522,22 +553,24 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca
handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ;
if(iter == mHandleEntryMap.end()) //no cache
{
+ llwarns << "No handle map entry for " << handle << llendl;
return ;
}
std::string filename;
getObjectCacheFilename(handle, filename);
- LLAPRFile* apr_file = new LLAPRFile(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp);
+ LLAPRFile* apr_file = new LLAPRFile(filename, APR_FOPEN_READ|APR_FOPEN_BINARY, mLocalAPRFilePoolp);
LLUUID cache_id ;
if(!checkRead(apr_file, cache_id.mData, UUID_BYTES))
{
+ llwarns << "Error reading cache_id from " << filename << llendl;
+ delete apr_file;
return ;
}
if(cache_id != id)
{
- llinfos << "Cache ID doesn't match for this region, discarding"<< llendl;
-
+ llwarns << "Cache ID (" << cache_id << ") doesn't match id for this region (" << id << "), discarding. handle = " << handle << llendl;
delete apr_file ;
return ;
}
@@ -545,6 +578,8 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca
S32 num_entries;
if(!checkRead(apr_file, &num_entries, sizeof(S32)))
{
+ llwarns << "Error reading num_entries from " << filename << llendl;
+ delete apr_file;
return ;
}
@@ -553,13 +588,12 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca
LLVOCacheEntry* entry = new LLVOCacheEntry(apr_file);
if (!entry->getLocalID())
{
- llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl;
+ llwarns << "Aborting cache file load for " << filename << ", cache file corruption! (entry number = " << i << ")" << llendl;
delete entry ;
break;
}
cache_entry_map[entry->getLocalID()] = entry;
}
- num_entries = cache_entry_map.size() ;
delete apr_file ;
return ;
@@ -567,86 +601,104 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca
void LLVOCache::purgeEntries()
{
- U32 limit = mCacheSize - NUM_ENTRIES_TO_PURGE ;
- while(mHeaderEntryQueue.size() > limit)
- {
- header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ;
- HeaderEntryInfo* entry = *iter ;
+ U32 limit = mCacheSize - (mCacheSize / ENTRIES_PURGE_FACTOR);
+ limit = llclamp(limit, (U32)1, mCacheSize);
+ // Construct a vector of entries out of the map so we can sort by time.
+ std::vector<HeaderEntryInfo*> header_vector;
+ handle_entry_map_t::iterator iter_end = mHandleEntryMap.end();
+ for (handle_entry_map_t::iterator iter = mHandleEntryMap.begin();
+ iter != iter_end;
+ ++iter)
+ {
+ header_vector.push_back(iter->second);
+ }
+ // Sort by time, oldest first.
+ std::sort(header_vector.begin(), header_vector.end(), header_entry_less());
+ while(header_vector.size() > limit)
+ {
+ HeaderEntryInfo* entry = header_vector.front();
- removeFromCache(entry->mHandle) ;
- mHandleEntryMap.erase(entry->mHandle) ;
- mHeaderEntryQueue.erase(iter) ;
- delete entry ;
+ removeFromCache(entry->mHandle);
+ mHandleEntryMap.erase(entry->mHandle);
+ header_vector.erase(header_vector.begin());
+ delete entry;
}
writeCacheHeader() ;
+ // *TODO: Verify that we can avoid re-reading the cache header. DK 2010-12-14
readCacheHeader() ;
- mNumEntries = mHandleEntryMap.size() ;
}
void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache)
{
if(!mEnabled)
{
+ llwarns << "Not writing cache for handle " << handle << "): Cache is currently disabled." << llendl;
return ;
}
llassert_always(mInitialized);
if(mReadOnly)
{
+ llwarns << "Not writing cache for handle " << handle << "): Cache is currently in read-only mode." << llendl;
return ;
}
+ U32 num_handle_entries = mHandleEntryMap.size();
+
HeaderEntryInfo* entry;
handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ;
if(iter == mHandleEntryMap.end()) //new entry
- {
- if(mNumEntries >= mCacheSize)
+ {
+ if(num_handle_entries >= mCacheSize)
{
purgeEntries() ;
+ num_handle_entries = mHandleEntryMap.size();
}
entry = new HeaderEntryInfo();
entry->mHandle = handle ;
entry->mTime = time(NULL) ;
- entry->mIndex = mNumEntries++ ;
- mHeaderEntryQueue.insert(entry) ;
+ entry->mIndex = num_handle_entries++;
mHandleEntryMap[handle] = entry ;
}
else
{
+ // Update access time.
entry = iter->second ;
entry->mTime = time(NULL) ;
-
- //resort
- mHeaderEntryQueue.erase(entry) ;
- mHeaderEntryQueue.insert(entry) ;
}
//update cache header
if(!updateEntry(entry))
{
+ llwarns << "Failed to update cache header index " << entry->mIndex << ". handle = " << handle << llendl;
return ; //update failed.
}
if(!dirty_cache)
{
+ llwarns << "Skipping write to cache for handle " << handle << ": cache not dirty" << llendl;
return ; //nothing changed, no need to update.
}
//write to cache file
std::string filename;
getObjectCacheFilename(handle, filename);
- LLAPRFile* apr_file = new LLAPRFile(filename, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
+ LLAPRFile* apr_file = new LLAPRFile(filename, APR_FOPEN_CREATE|APR_FOPEN_WRITE|APR_FOPEN_BINARY|APR_FOPEN_TRUNCATE, mLocalAPRFilePoolp);
if(!checkWrite(apr_file, (void*)id.mData, UUID_BYTES))
{
+ llwarns << "Error writing id to " << filename << llendl;
+ delete apr_file;
return ;
}
S32 num_entries = cache_entry_map.size() ;
if(!checkWrite(apr_file, &num_entries, sizeof(S32)))
{
+ llwarns << "Error writing num_entries to " << filename << llendl;
+ delete apr_file;
return ;
}
@@ -654,10 +706,10 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry:
{
if(!iter->second->writeToFile(apr_file))
{
+ llwarns << "Aborting cache file write for " << filename << ", error writing to file!" << llendl;
//failed
- delete apr_file ;
removeCache() ;
- return ;
+ break;
}
}
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index ed2bc8bafe..e103007979 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -95,10 +95,13 @@ private:
{
bool operator()(const HeaderEntryInfo* lhs, const HeaderEntryInfo* rhs) const
{
- return lhs->mTime < rhs->mTime; // older entry in front of queue (set)
+ if (lhs->mTime == rhs->mTime)
+ {
+ return lhs->mHandle < rhs->mHandle;
+ }
+ return lhs->mTime < rhs->mTime; // older entry in front
}
};
- typedef std::set<HeaderEntryInfo*, header_entry_less> header_entry_queue_t;
typedef std::map<U64, HeaderEntryInfo*> handle_entry_map_t;
private:
LLVOCache() ;
@@ -125,8 +128,8 @@ private:
void removeCache() ;
void purgeEntries();
BOOL updateEntry(const HeaderEntryInfo* entry);
- BOOL checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes) ;
- BOOL checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes) ;
+ BOOL checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error = true) ;
+ BOOL checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error = true) ;
private:
BOOL mEnabled;
@@ -134,11 +137,9 @@ private:
BOOL mReadOnly ;
HeaderMetaInfo mMetaInfo;
U32 mCacheSize;
- U32 mNumEntries;
std::string mHeaderFileName ;
std::string mObjectCacheDirName;
LLVolatileAPRPool* mLocalAPRFilePoolp ;
- header_entry_queue_t mHeaderEntryQueue;
handle_entry_map_t mHandleEntryMap;
static LLVOCache* sInstance ;
diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp
index d239347810..4f6ec4ca61 100644
--- a/indra/newview/llwaterparammanager.cpp
+++ b/indra/newview/llwaterparammanager.cpp
@@ -33,6 +33,7 @@
#include "pipeline.h"
#include "llsky.h"
+#include "lldiriterator.h"
#include "llfloaterreg.h"
#include "llsliderctrl.h"
#include "llspinctrl.h"
@@ -85,11 +86,12 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name)
std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/water", ""));
LL_DEBUGS2("AppInit", "Shaders") << "Loading Default water settings from " << path_name << LL_ENDL;
- bool found = true;
+ bool found = true;
+ LLDirIterator app_settings_iter(path_name, "*.xml");
while(found)
{
std::string name;
- found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name);
+ found = app_settings_iter.next(name);
if(found)
{
@@ -111,11 +113,12 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name)
std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/water", ""));
LL_DEBUGS2("AppInit", "Shaders") << "Loading User water settings from " << path_name2 << LL_ENDL;
- found = true;
+ found = true;
+ LLDirIterator user_settings_iter(path_name2, "*.xml");
while(found)
{
std::string name;
- found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name);
+ found = user_settings_iter.next(name);
if(found)
{
name=name.erase(name.length()-4);
diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp
index e5f52dfc97..848efcbb49 100644
--- a/indra/newview/llwlparammanager.cpp
+++ b/indra/newview/llwlparammanager.cpp
@@ -31,6 +31,7 @@
#include "pipeline.h"
#include "llsky.h"
+#include "lldiriterator.h"
#include "llfloaterreg.h"
#include "llsliderctrl.h"
#include "llspinctrl.h"
@@ -100,11 +101,12 @@ void LLWLParamManager::loadPresets(const std::string& file_name)
std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", ""));
LL_DEBUGS2("AppInit", "Shaders") << "Loading Default WindLight settings from " << path_name << LL_ENDL;
- bool found = true;
+ bool found = true;
+ LLDirIterator app_settings_iter(path_name, "*.xml");
while(found)
{
std::string name;
- found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name);
+ found = app_settings_iter.next(name);
if(found)
{
@@ -126,11 +128,12 @@ void LLWLParamManager::loadPresets(const std::string& file_name)
std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", ""));
LL_DEBUGS2("AppInit", "Shaders") << "Loading User WindLight settings from " << path_name2 << LL_ENDL;
- found = true;
+ found = true;
+ LLDirIterator user_settings_iter(path_name2, "*.xml");
while(found)
{
std::string name;
- found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name);
+ found = user_settings_iter.next(name);
if(found)
{
name=name.erase(name.length()-4);
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 3f785a99fe..cef3d87f36 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -424,6 +424,7 @@ public:
RENDER_DEBUG_AVATAR_VOLUME = 0x0100000,
RENDER_DEBUG_BUILD_QUEUE = 0x0200000,
RENDER_DEBUG_AGENT_TARGET = 0x0400000,
+ RENDER_DEBUG_UPDATE_TYPE = 0x0800000,
};
public:
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index 62441fd984..75aec21f93 100644
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -115,9 +115,6 @@
name="AlertCautionTextColor"
reference="LtYellow" />
<color
- name="AgentLinkColor"
- reference="EmphasisColor" />
- <color
name="AlertTextColor"
value="0.58 0.66 0.84 1" />
<color
@@ -349,9 +346,6 @@
name="GridlineShadowColor"
value="0 0 0 0.31" />
<color
- name="GroupLinkColor"
- reference="White" />
- <color
name="GroupNotifyBoxColor"
value="0.3344 0.5456 0.5159 1" />
<color
diff --git a/indra/newview/skins/default/xui/da/notifications.xml b/indra/newview/skins/default/xui/da/notifications.xml
index 70299c61b4..593e686d4c 100644
--- a/indra/newview/skins/default/xui/da/notifications.xml
+++ b/indra/newview/skins/default/xui/da/notifications.xml
@@ -1636,7 +1636,7 @@ Knappen vil blive vist når der er nok plads til den.
<notification name="ShareItemsConfirmation">
Er du sikker på at du vil dele følgende genstande:
-[ITEMS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
Med følgende beboere:
diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml
index 06cc02cd84..a2d0b5a170 100644
--- a/indra/newview/skins/default/xui/de/notifications.xml
+++ b/indra/newview/skins/default/xui/de/notifications.xml
@@ -2747,7 +2747,7 @@ Die Schaltfläche wird angezeigt, wenn genügend Platz vorhanden ist.
<notification name="ShareItemsConfirmation">
Möchten Sie diese Objekte wirklich für andere freigeben:
-[ITEMS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
Für folgende Einwohner:
diff --git a/indra/newview/skins/default/xui/en/floater_web_content.xml b/indra/newview/skins/default/xui/en/floater_web_content.xml
index 2ad46824c2..d90d0feda9 100644
--- a/indra/newview/skins/default/xui/en/floater_web_content.xml
+++ b/indra/newview/skins/default/xui/en/floater_web_content.xml
@@ -1,190 +1,190 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<floater
- legacy_header_height="18"
- can_resize="true"
- height="440"
- layout="topleft"
- min_height="140"
- min_width="467"
- name="floater_web_content"
- help_topic="floater_web_content"
- save_rect="true"
- auto_tile="true"
- title=""
- initial_mime_type="text/html"
- width="820">
- <layout_stack
- bottom="440"
- follows="left|right|top|bottom"
- layout="topleft"
- left="5"
- name="stack1"
- orientation="vertical"
- top="20"
- width="810">
- <layout_panel
- auto_resize="false"
- default_tab_group="1"
- height="22"
- layout="topleft"
- left="0"
- min_height="20"
- name="nav_controls"
- top="400"
- user_resize="false"
- width="800">
- <button
- image_overlay="Arrow_Left_Off"
- image_disabled="PushButton_Disabled"
- image_disabled_selected="PushButton_Disabled"
- image_selected="PushButton_Selected"
- image_unselected="PushButton_Off"
- hover_glow_amount="0.15"
- tool_tip="Navigate back"
- follows="left|top"
- height="22"
- layout="topleft"
- left="1"
- name="back"
- top="0"
- width="22">
- <button.commit_callback
- function="WebContent.Back" />
- </button>
- <button
- image_overlay="Arrow_Right_Off"
- image_disabled="PushButton_Disabled"
- image_disabled_selected="PushButton_Disabled"
- image_selected="PushButton_Selected"
- image_unselected="PushButton_Off"
- tool_tip="Navigate forward"
- follows="left|top"
- height="22"
- layout="topleft"
- left="27"
- name="forward"
- top_delta="0"
- width="22">
- <button.commit_callback
- function="WebContent.Forward" />
- </button>
- <button
- image_overlay="Stop_Off"
- image_disabled="PushButton_Disabled"
- image_disabled_selected="PushButton_Disabled"
- image_selected="PushButton_Selected"
- image_unselected="PushButton_Off"
- tool_tip="Stop navigation"
- enabled="true"
- follows="left|top"
- height="22"
- layout="topleft"
- left="51"
- name="stop"
- top_delta="0"
- width="22">
- <button.commit_callback
- function="WebContent.Stop" />
- </button>
- <button
- image_overlay="Refresh_Off"
- image_disabled="PushButton_Disabled"
- image_disabled_selected="PushButton_Disabled"
- image_selected="PushButton_Selected"
- image_unselected="PushButton_Off"
- tool_tip="Reload page"
- follows="left|top"
- height="22"
- layout="topleft"
- left="51"
- name="reload"
- top_delta="0"
- width="22">
- <button.commit_callback
- function="WebContent.Reload" />
- </button>
- <combo_box
- allow_text_entry="true"
- follows="left|top|right"
- tab_group="1"
- height="22"
- layout="topleft"
- left_pad="4"
- max_chars="1024"
- name="address"
- combo_editor.select_on_focus="true"
- tool_tip="Enter URL here"
- top_delta="0"
- width="702">
- <combo_box.commit_callback
- function="WebContent.EnterAddress" />
- </combo_box>
- <icon
- name="media_secure_lock_flag"
- height="16"
- follows="top|right"
- image_name="Lock2"
- layout="topleft"
- left_delta="656"
- top_delta="2"
- visible="false"
- tool_tip="Secured Browsing"
- width="16" />
- <button
- image_overlay="ExternalBrowser_Off"
- image_disabled="PushButton_Disabled"
- image_disabled_selected="PushButton_Disabled"
- image_selected="PushButton_Selected"
- image_unselected="PushButton_Off"
- tool_tip="Open current URL in your desktop browser"
- follows="right|top"
- enabled="true"
- height="22"
- layout="topleft"
- name="popexternal"
- right="800"
- top_delta="-2"
- width="22">
- <button.commit_callback
- function="WebContent.PopExternal" />
- </button>
- </layout_panel>
- <layout_panel
- height="40"
- layout="topleft"
- left_delta="0"
- name="external_controls"
- top_delta="0"
- user_resize="false"
- width="540">
- <web_browser
- bottom="-22"
- follows="all"
- layout="topleft"
- left="0"
- name="webbrowser"
- top="0"/>
- <text
- type="string"
- length="100"
- follows="bottom|left"
- height="20"
- layout="topleft"
- left_delta="0"
- name="statusbartext"
- parse_urls="false"
- text_color="0.4 0.4 0.4 1"
- top_pad="5"
- width="452"/>
- <progress_bar
- color_bar="0.3 1.0 0.3 1"
- follows="bottom|right"
- height="16"
- top_delta="-1"
- left_pad="24"
- layout="topleft"
- name="statusbarprogress"
- width="64"/>
- </layout_panel>
- </layout_stack>
-</floater>
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ can_resize="true"
+ height="440"
+ layout="topleft"
+ min_height="140"
+ min_width="467"
+ name="floater_web_content"
+ help_topic="floater_web_content"
+ save_rect="true"
+ auto_tile="true"
+ title=""
+ initial_mime_type="text/html"
+ width="820">
+ <layout_stack
+ bottom="440"
+ follows="left|right|top|bottom"
+ layout="topleft"
+ left="5"
+ name="stack1"
+ orientation="vertical"
+ top="20"
+ width="810">
+ <layout_panel
+ auto_resize="false"
+ default_tab_group="1"
+ height="22"
+ layout="topleft"
+ left="0"
+ min_height="20"
+ name="nav_controls"
+ top="400"
+ user_resize="false"
+ width="800">
+ <button
+ image_overlay="Arrow_Left_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ hover_glow_amount="0.15"
+ tool_tip="Navigate back"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="1"
+ name="back"
+ top="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Back" />
+ </button>
+ <button
+ image_overlay="Arrow_Right_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ tool_tip="Navigate forward"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="27"
+ name="forward"
+ top_delta="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Forward" />
+ </button>
+ <button
+ image_overlay="Stop_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ tool_tip="Stop navigation"
+ enabled="true"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="51"
+ name="stop"
+ top_delta="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Stop" />
+ </button>
+ <button
+ image_overlay="Refresh_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ tool_tip="Reload page"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="51"
+ name="reload"
+ top_delta="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Reload" />
+ </button>
+ <combo_box
+ allow_text_entry="true"
+ follows="left|top|right"
+ tab_group="1"
+ height="22"
+ layout="topleft"
+ left_pad="4"
+ max_chars="1024"
+ name="address"
+ combo_editor.select_on_focus="true"
+ tool_tip="Enter URL here"
+ top_delta="0"
+ width="702">
+ <combo_box.commit_callback
+ function="WebContent.EnterAddress" />
+ </combo_box>
+ <icon
+ name="media_secure_lock_flag"
+ height="16"
+ follows="top|right"
+ image_name="Lock2"
+ layout="topleft"
+ left_delta="656"
+ top_delta="2"
+ visible="false"
+ tool_tip="Secured Browsing"
+ width="16" />
+ <button
+ image_overlay="ExternalBrowser_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ tool_tip="Open current URL in your desktop browser"
+ follows="right|top"
+ enabled="true"
+ height="22"
+ layout="topleft"
+ name="popexternal"
+ right="800"
+ top_delta="-2"
+ width="22">
+ <button.commit_callback
+ function="WebContent.PopExternal" />
+ </button>
+ </layout_panel>
+ <layout_panel
+ height="40"
+ layout="topleft"
+ left_delta="0"
+ name="external_controls"
+ top_delta="0"
+ user_resize="false"
+ width="540">
+ <web_browser
+ bottom="-22"
+ follows="all"
+ layout="topleft"
+ left="0"
+ name="webbrowser"
+ top="0"/>
+ <text
+ type="string"
+ length="100"
+ follows="bottom|left"
+ height="20"
+ layout="topleft"
+ left_delta="0"
+ name="statusbartext"
+ parse_urls="false"
+ text_color="0.4 0.4 0.4 1"
+ top_pad="5"
+ width="452"/>
+ <progress_bar
+ color_bar="0.3 1.0 0.3 1"
+ follows="bottom|right"
+ height="16"
+ top_delta="-1"
+ left_pad="24"
+ layout="topleft"
+ name="statusbarprogress"
+ width="64"/>
+ </layout_panel>
+ </layout_stack>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/menu_object.xml b/indra/newview/skins/default/xui/en/menu_object.xml
index c751aa4e0c..719509301b 100644
--- a/indra/newview/skins/default/xui/en/menu_object.xml
+++ b/indra/newview/skins/default/xui/en/menu_object.xml
@@ -100,7 +100,7 @@
name="Object Attach HUD" />
</context_menu>
<context_menu
- label="Remove"
+ label="Manage"
name="Remove">
<menu_item_call
enabled="false"
@@ -129,15 +129,6 @@
<menu_item_call.on_enable
function="Object.EnableReturn" />
</menu_item_call>
- <menu_item_call
- enabled="false"
- label="Delete"
- name="Delete">
- <menu_item_call.on_click
- function="Object.Delete" />
- <menu_item_call.on_enable
- function="Object.EnableDelete" />
- </menu_item_call>
</context_menu>
<menu_item_separator layout="topleft" />
<menu_item_call
@@ -176,4 +167,13 @@
<menu_item_call.on_enable
function="Object.EnableBuy" />
</menu_item_call>
+ <menu_item_call
+ enabled="false"
+ label="Delete"
+ name="Delete">
+ <menu_item_call.on_click
+ function="Object.Delete" />
+ <menu_item_call.on_enable
+ function="Object.EnableDelete" />
+ </menu_item_call>
</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index d997a262a8..2207e418c8 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2153,6 +2153,16 @@
parameter="render batches" />
</menu_item_check>
<menu_item_check
+ label="Update Type"
+ name="Update Type">
+ <menu_item_check.on_check
+ function="Advanced.CheckInfoDisplay"
+ parameter="update type" />
+ <menu_item_check.on_click
+ function="Advanced.ToggleInfoDisplay"
+ parameter="update type" />
+ </menu_item_check>
+ <menu_item_check
label="Texture Anim"
name="Texture Anim">
<menu_item_check.on_check
@@ -2717,6 +2727,18 @@
function="Floater.Toggle"
parameter="region_debug_console" />
</menu_item_check>
+ <menu_item_check
+ label="Region Debug Console"
+ name="Region Debug Console"
+ shortcut="control|shift|`"
+ use_mac_ctrl="true">
+ <menu_item_check.on_check
+ function="Floater.Visible"
+ parameter="region_debug_console" />
+ <menu_item_check.on_click
+ function="Floater.Toggle"
+ parameter="region_debug_console" />
+ </menu_item_check>
<menu_item_separator />
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 3df53ac442..6f21938bdb 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6431,7 +6431,7 @@ Select residents to share with.
type="alertmodal">
Are you sure you want to share the following items:
-[ITEMS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
With the following Residents:
diff --git a/indra/newview/skins/default/xui/en/panel_group_land_money.xml b/indra/newview/skins/default/xui/en/panel_group_land_money.xml
index 61d6cbb2d0..eff674c628 100644
--- a/indra/newview/skins/default/xui/en/panel_group_land_money.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_land_money.xml
@@ -67,23 +67,23 @@
<scroll_list.columns
label="Parcel"
name="name"
- width="47" />
+ relative_width="0.2" />
<scroll_list.columns
label="Region"
name="location"
- width="47" />
+ relative_width="0.2" />
<scroll_list.columns
label="Type"
name="type"
- width="47" />
+ relative_width="0.2" />
<scroll_list.columns
label="Area"
name="area"
- width="47" />
+ relative_width="0.2" />
<scroll_list.columns
label="Hidden"
name="hidden"
- width="47" />
+ relative_width="0.2" />
</scroll_list>
<text
type="string"
diff --git a/indra/newview/skins/default/xui/en/widgets/floater.xml b/indra/newview/skins/default/xui/en/widgets/floater.xml
index 85d0c633af..2e5ebafe46 100644
--- a/indra/newview/skins/default/xui/en/widgets/floater.xml
+++ b/indra/newview/skins/default/xui/en/widgets/floater.xml
@@ -21,4 +21,5 @@
tear_off_pressed_image="tearoff_pressed.tga"
dock_pressed_image="Icon_Dock_Press"
help_pressed_image="Icon_Help_Press"
+ focus_root="true"
/>
diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml
index 2dd7a6b0f5..14ce39e8fc 100644
--- a/indra/newview/skins/default/xui/es/notifications.xml
+++ b/indra/newview/skins/default/xui/es/notifications.xml
@@ -2734,7 +2734,7 @@ Se mostrará cuando haya suficiente espacio.
<notification name="ShareItemsConfirmation">
¿Estás seguro de que quieres compartir los elementos siguientes?
-[ITEMS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
Con los siguientes residentes:
diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml
index ec362d7f22..f0b0e63af0 100644
--- a/indra/newview/skins/default/xui/fr/notifications.xml
+++ b/indra/newview/skins/default/xui/fr/notifications.xml
@@ -2730,7 +2730,7 @@ Le bouton sera affiché quand il y aura suffisamment de place.
<notification name="ShareItemsConfirmation">
Voulez-vous vraiment partager les articles suivants :
-[ITEMS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
avec les résidents suivants :
diff --git a/indra/newview/skins/default/xui/it/notifications.xml b/indra/newview/skins/default/xui/it/notifications.xml
index 32483881b2..5e53080c77 100644
--- a/indra/newview/skins/default/xui/it/notifications.xml
+++ b/indra/newview/skins/default/xui/it/notifications.xml
@@ -2679,7 +2679,7 @@ Il pulsante verrà visualizzato quando lo spazio sarà sufficiente.
<notification name="ShareItemsConfirmation">
Sei sicuro di volere condividere gli oggetti
-[ITEMS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
Con i seguenti residenti?
diff --git a/indra/newview/skins/default/xui/ja/notifications.xml b/indra/newview/skins/default/xui/ja/notifications.xml
index c0af0e03ff..f133bb361a 100644
--- a/indra/newview/skins/default/xui/ja/notifications.xml
+++ b/indra/newview/skins/default/xui/ja/notifications.xml
@@ -2731,7 +2731,7 @@ M キーを押して変更します。
<notification name="ShareItemsConfirmation">
次のアイテムを共有しますか:
-[ITEMS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
次の住人と共有しますか:
diff --git a/indra/newview/skins/default/xui/pl/notifications.xml b/indra/newview/skins/default/xui/pl/notifications.xml
index 8151c7eb93..57a6b8b8ef 100644
--- a/indra/newview/skins/default/xui/pl/notifications.xml
+++ b/indra/newview/skins/default/xui/pl/notifications.xml
@@ -2691,7 +2691,7 @@ Przycisk zostanie wyświetlony w przypadku dostatecznej ilości przestrzeni.
<notification name="ShareItemsConfirmation">
Jesteś pewien/pewna, że chcesz udostępnić następujące obiekty:
-[ITEMS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
następującym Rezydentom:
diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml
index dc38b740aa..a1855f2e89 100644
--- a/indra/newview/skins/default/xui/pt/notifications.xml
+++ b/indra/newview/skins/default/xui/pt/notifications.xml
@@ -477,7 +477,7 @@ Para aumentar a qualidade do vídeo, vá para Preferências &gt; Vídeo.
</notification>
<notification name="CannotCopyWarning">
Você não tem autorização para copiar os itens abaixo:
-[ITENS]
+[ITEMS]
ao dá-los, você ficará sem eles no seu inventário. Deseja realmente dar estes itens?
<usetemplate name="okcancelbuttons" notext="Não" yestext="Sim"/>
</notification>
@@ -2714,7 +2714,7 @@ O botão será exibido quando houver espaço suficente.
<notification name="ShareItemsConfirmation">
Tem certeza de que quer compartilhar os items abaixo?
-[ITENS]
+&lt;nolink&gt;[ITEMS]&lt;/nolink&gt;
Com os seguintes residentes:
diff --git a/indra/newview/tests/llremoteparcelrequest_test.cpp b/indra/newview/tests/llremoteparcelrequest_test.cpp
index a6c1f69c82..7862cce3a1 100644
--- a/indra/newview/tests/llremoteparcelrequest_test.cpp
+++ b/indra/newview/tests/llremoteparcelrequest_test.cpp
@@ -1,134 +1,136 @@
-/**
- * @file llremoteparcelrequest_test.cpp
- * @author Brad Kittenbrink <brad@lindenlab.com>
- *
- * $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 "../test/lltut.h"
-
-#include "../llremoteparcelrequest.h"
-
-#include "../llagent.h"
-#include "message.h"
-
-namespace {
- LLControlGroup s_saved_settings("dummy_settings");
- const LLUUID TEST_PARCEL_ID("11111111-1111-1111-1111-111111111111");
-}
-
-LLCurl::Responder::Responder() { }
-LLCurl::Responder::~Responder() { }
-void LLCurl::Responder::error(U32,std::string const &) { }
-void LLCurl::Responder::result(LLSD const &) { }
-void LLCurl::Responder::errorWithContent(U32 status,std::string const &,LLSD const &) { }
-void LLCurl::Responder::completedRaw(U32 status, std::string const &, LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { }
-void LLCurl::Responder::completed(U32 status, std::string const &, LLSD const &) { }
-void LLCurl::Responder::completedHeader(U32 status, std::string const &, LLSD const &) { }
-void LLMessageSystem::getF32(char const *,char const *,F32 &,S32) { }
-void LLMessageSystem::getU8(char const *,char const *,U8 &,S32) { }
-void LLMessageSystem::getS32(char const *,char const *,S32 &,S32) { }
-void LLMessageSystem::getString(char const *,char const *, std::string &,S32) { }
-void LLMessageSystem::getUUID(char const *,char const *, LLUUID & out_id,S32)
-{
- out_id = TEST_PARCEL_ID;
-}
-void LLMessageSystem::nextBlock(char const *) { }
-void LLMessageSystem::addUUID(char const *,LLUUID const &) { }
-void LLMessageSystem::addUUIDFast(char const *,LLUUID const &) { }
-void LLMessageSystem::nextBlockFast(char const *) { }
-void LLMessageSystem::newMessage(char const *) { }
-LLMessageSystem * gMessageSystem;
-char * _PREHASH_AgentID;
-char * _PREHASH_AgentData;
-LLAgent gAgent;
-LLAgent::LLAgent() : mAgentAccess(s_saved_settings) { }
-LLAgent::~LLAgent() { }
-void LLAgent::sendReliableMessage(void) { }
-LLUUID gAgentSessionID;
-LLUUID gAgentID;
-LLUIColor::LLUIColor(void) { }
-LLAgentAccess::LLAgentAccess(LLControlGroup & settings) : mSavedSettings(settings) { }
-LLControlGroup::LLControlGroup(std::string const & name) : LLInstanceTracker<LLControlGroup, std::string>(name) { }
-LLControlGroup::~LLControlGroup(void) { }
-
-namespace tut
-{
- struct TestObserver : public LLRemoteParcelInfoObserver {
- TestObserver() : mProcessed(false) { }
-
- virtual void processParcelInfo(const LLParcelData& parcel_data)
- {
- mProcessed = true;
- }
-
- virtual void setParcelID(const LLUUID& parcel_id) { }
-
- virtual void setErrorStatus(U32 status, const std::string& reason) { }
-
- bool mProcessed;
- };
-
- struct RemoteParcelRequestData
- {
- RemoteParcelRequestData()
- {
- }
- };
-
- typedef test_group<RemoteParcelRequestData> remoteparcelrequest_t;
- typedef remoteparcelrequest_t::object remoteparcelrequest_object_t;
- tut::remoteparcelrequest_t tut_remoteparcelrequest("LLRemoteParcelRequest");
-
- template<> template<>
- void remoteparcelrequest_object_t::test<1>()
- {
- set_test_name("observer pointer");
-
- boost::scoped_ptr<TestObserver> observer(new TestObserver());
-
- LLRemoteParcelInfoProcessor & processor = LLRemoteParcelInfoProcessor::instance();
- processor.addObserver(LLUUID(TEST_PARCEL_ID), observer.get());
-
- processor.processParcelInfoReply(gMessageSystem, NULL);
-
- ensure(observer->mProcessed);
- }
-
- template<> template<>
- void remoteparcelrequest_object_t::test<2>()
- {
- set_test_name("CHOP-220: dangling observer pointer");
-
- LLRemoteParcelInfoObserver * observer = new TestObserver();
-
- LLRemoteParcelInfoProcessor & processor = LLRemoteParcelInfoProcessor::instance();
- processor.addObserver(LLUUID(TEST_PARCEL_ID), observer);
-
- delete observer;
- observer = NULL;
-
- processor.processParcelInfoReply(gMessageSystem, NULL);
- }
-}
+/**
+ * @file llremoteparcelrequest_test.cpp
+ * @author Brad Kittenbrink <brad@lindenlab.com>
+ *
+ * $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 "../test/lltut.h"
+
+#include "../llremoteparcelrequest.h"
+
+#include "../llagent.h"
+#include "message.h"
+#include "llurlentry.h"
+
+namespace {
+ LLControlGroup s_saved_settings("dummy_settings");
+ const LLUUID TEST_PARCEL_ID("11111111-1111-1111-1111-111111111111");
+}
+
+LLCurl::Responder::Responder() { }
+LLCurl::Responder::~Responder() { }
+void LLCurl::Responder::error(U32,std::string const &) { }
+void LLCurl::Responder::result(LLSD const &) { }
+void LLCurl::Responder::errorWithContent(U32 status,std::string const &,LLSD const &) { }
+void LLCurl::Responder::completedRaw(U32 status, std::string const &, LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { }
+void LLCurl::Responder::completed(U32 status, std::string const &, LLSD const &) { }
+void LLCurl::Responder::completedHeader(U32 status, std::string const &, LLSD const &) { }
+void LLMessageSystem::getF32(char const *,char const *,F32 &,S32) { }
+void LLMessageSystem::getU8(char const *,char const *,U8 &,S32) { }
+void LLMessageSystem::getS32(char const *,char const *,S32 &,S32) { }
+void LLMessageSystem::getString(char const *,char const *, std::string &,S32) { }
+void LLMessageSystem::getUUID(char const *,char const *, LLUUID & out_id,S32)
+{
+ out_id = TEST_PARCEL_ID;
+}
+void LLMessageSystem::nextBlock(char const *) { }
+void LLMessageSystem::addUUID(char const *,LLUUID const &) { }
+void LLMessageSystem::addUUIDFast(char const *,LLUUID const &) { }
+void LLMessageSystem::nextBlockFast(char const *) { }
+void LLMessageSystem::newMessage(char const *) { }
+LLMessageSystem * gMessageSystem;
+char * _PREHASH_AgentID;
+char * _PREHASH_AgentData;
+LLAgent gAgent;
+LLAgent::LLAgent() : mAgentAccess(s_saved_settings) { }
+LLAgent::~LLAgent() { }
+void LLAgent::sendReliableMessage(void) { }
+LLUUID gAgentSessionID;
+LLUUID gAgentID;
+LLUIColor::LLUIColor(void) { }
+LLAgentAccess::LLAgentAccess(LLControlGroup & settings) : mSavedSettings(settings) { }
+LLControlGroup::LLControlGroup(std::string const & name) : LLInstanceTracker<LLControlGroup, std::string>(name) { }
+LLControlGroup::~LLControlGroup(void) { }
+void LLUrlEntryParcel::processParcelInfo(const LLUrlEntryParcel::LLParcelData& parcel_data) { }
+
+namespace tut
+{
+ struct TestObserver : public LLRemoteParcelInfoObserver {
+ TestObserver() : mProcessed(false) { }
+
+ virtual void processParcelInfo(const LLParcelData& parcel_data)
+ {
+ mProcessed = true;
+ }
+
+ virtual void setParcelID(const LLUUID& parcel_id) { }
+
+ virtual void setErrorStatus(U32 status, const std::string& reason) { }
+
+ bool mProcessed;
+ };
+
+ struct RemoteParcelRequestData
+ {
+ RemoteParcelRequestData()
+ {
+ }
+ };
+
+ typedef test_group<RemoteParcelRequestData> remoteparcelrequest_t;
+ typedef remoteparcelrequest_t::object remoteparcelrequest_object_t;
+ tut::remoteparcelrequest_t tut_remoteparcelrequest("LLRemoteParcelRequest");
+
+ template<> template<>
+ void remoteparcelrequest_object_t::test<1>()
+ {
+ set_test_name("observer pointer");
+
+ boost::scoped_ptr<TestObserver> observer(new TestObserver());
+
+ LLRemoteParcelInfoProcessor & processor = LLRemoteParcelInfoProcessor::instance();
+ processor.addObserver(LLUUID(TEST_PARCEL_ID), observer.get());
+
+ processor.processParcelInfoReply(gMessageSystem, NULL);
+
+ ensure(observer->mProcessed);
+ }
+
+ template<> template<>
+ void remoteparcelrequest_object_t::test<2>()
+ {
+ set_test_name("CHOP-220: dangling observer pointer");
+
+ LLRemoteParcelInfoObserver * observer = new TestObserver();
+
+ LLRemoteParcelInfoProcessor & processor = LLRemoteParcelInfoProcessor::instance();
+ processor.addObserver(LLUUID(TEST_PARCEL_ID), observer);
+
+ delete observer;
+ observer = NULL;
+
+ processor.processParcelInfoReply(gMessageSystem, NULL);
+ }
+}
diff --git a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp
index 5f8cd28f29..e19d5724f1 100644
--- a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp
+++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp
@@ -1,200 +1,194 @@
-/**
- * @file llupdaterservice_test.cpp
- * @brief Tests of llupdaterservice.cpp.
- *
- * $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$
- */
-
-// Precompiled header
-#include "linden_common.h"
-// associated header
-#include "../llupdaterservice.h"
-#include "../llupdatechecker.h"
-#include "../llupdatedownloader.h"
-#include "../llupdateinstaller.h"
-
-#include "../../../test/lltut.h"
-//#define DEBUG_ON
-#include "../../../test/debug.h"
-
-#include "llevents.h"
-#include "lldir.h"
-
-/*****************************************************************************
-* MOCK'd
-*****************************************************************************/
-LLUpdateChecker::LLUpdateChecker(LLUpdateChecker::Client & client)
-{}
-void LLUpdateChecker::check(std::string const & protocolVersion, std::string const & hostUrl,
- std::string const & servicePath, std::string channel, std::string version)
-{}
-LLUpdateDownloader::LLUpdateDownloader(Client & ) {}
-void LLUpdateDownloader::download(LLURI const & , std::string const &, std::string const &, bool){}
-
-class LLDir_Mock : public LLDir
-{
- void initAppDirs(const std::string &app_name,
- const std::string& app_read_only_data_dir = "") {}
- U32 countFilesInDir(const std::string &dirname, const std::string &mask)
- {
- return 0;
- }
-
- BOOL getNextFileInDir(const std::string &dirname,
- const std::string &mask,
- std::string &fname)
- {
- return false;
- }
- void getRandomFileInDir(const std::string &dirname,
- const std::string &mask,
- std::string &fname) {}
- std::string getCurPath() { return ""; }
- BOOL fileExists(const std::string &filename) const { return false; }
- std::string getLLPluginLauncher() { return ""; }
- std::string getLLPluginFilename(std::string base_name) { return ""; }
-
-} gDirUtil;
-LLDir* gDirUtilp = &gDirUtil;
-LLDir::LLDir() {}
-LLDir::~LLDir() {}
-S32 LLDir::deleteFilesInDir(const std::string &dirname,
- const std::string &mask)
-{ return 0; }
-
-void LLDir::setChatLogsDir(const std::string &path){}
-void LLDir::setPerAccountChatLogsDir(const std::string &username){}
-void LLDir::setLindenUserDir(const std::string &username){}
-void LLDir::setSkinFolder(const std::string &skin_folder){}
-bool LLDir::setCacheDir(const std::string &path){ return true; }
-void LLDir::dumpCurrentDirectories() {}
-
-std::string LLDir::getExpandedFilename(ELLPath location,
- const std::string &filename) const
-{
- return "";
-}
-
-std::string LLUpdateDownloader::downloadMarkerPath(void)
-{
- return "";
-}
-
-void LLUpdateDownloader::resume(void) {}
-void LLUpdateDownloader::cancel(void) {}
-void LLUpdateDownloader::setBandwidthLimit(U64 bytesPerSecond) {}
-
-int ll_install_update(std::string const &, std::string const &, bool, LLInstallScriptMode)
-{
- return 0;
-}
-
-std::string const & ll_install_failed_marker_path()
-{
- static std::string wubba;
- return wubba;
-}
-
-/*
-#pragma warning(disable: 4273)
-llus_mock_llifstream::llus_mock_llifstream(const std::string& _Filename,
- ios_base::openmode _Mode,
- int _Prot) :
- std::basic_istream<char,std::char_traits< char > >(NULL,true)
-{}
-
-llus_mock_llifstream::~llus_mock_llifstream() {}
-bool llus_mock_llifstream::is_open() const {return true;}
-void llus_mock_llifstream::close() {}
-*/
-
-/*****************************************************************************
-* TUT
-*****************************************************************************/
-namespace tut
-{
- struct llupdaterservice_data
- {
- llupdaterservice_data() :
- pumps(LLEventPumps::instance()),
- test_url("dummy_url"),
- test_channel("dummy_channel"),
- test_version("dummy_version")
- {}
- LLEventPumps& pumps;
- std::string test_url;
- std::string test_channel;
- std::string test_version;
- };
-
- typedef test_group<llupdaterservice_data> llupdaterservice_group;
- typedef llupdaterservice_group::object llupdaterservice_object;
- llupdaterservice_group llupdaterservicegrp("LLUpdaterService");
-
- template<> template<>
- void llupdaterservice_object::test<1>()
- {
- DEBUG;
- LLUpdaterService updater;
- bool got_usage_error = false;
- try
- {
- updater.startChecking();
- }
- catch(LLUpdaterService::UsageError)
- {
- got_usage_error = true;
- }
- ensure("Caught start before params", got_usage_error);
- }
-
- template<> template<>
- void llupdaterservice_object::test<2>()
- {
- DEBUG;
- LLUpdaterService updater;
- bool got_usage_error = false;
- try
- {
- updater.initialize("1.0",test_url, "update" ,test_channel, test_version);
- updater.startChecking();
- updater.initialize("1.0", "other_url", "update", test_channel, test_version);
- }
- catch(LLUpdaterService::UsageError)
- {
- got_usage_error = true;
- }
- ensure("Caught params while running", got_usage_error);
- }
-
- template<> template<>
- void llupdaterservice_object::test<3>()
- {
- DEBUG;
- LLUpdaterService updater;
- updater.initialize("1.0", test_url, "update", test_channel, test_version);
- updater.startChecking();
- ensure(updater.isChecking());
- updater.stopChecking();
- ensure(!updater.isChecking());
- }
-}
+/**
+ * @file llupdaterservice_test.cpp
+ * @brief Tests of llupdaterservice.cpp.
+ *
+ * $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$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "../llupdaterservice.h"
+#include "../llupdatechecker.h"
+#include "../llupdatedownloader.h"
+#include "../llupdateinstaller.h"
+
+#include "../../../test/lltut.h"
+//#define DEBUG_ON
+#include "../../../test/debug.h"
+
+#include "llevents.h"
+#include "lldir.h"
+
+/*****************************************************************************
+* MOCK'd
+*****************************************************************************/
+LLUpdateChecker::LLUpdateChecker(LLUpdateChecker::Client & client)
+{}
+void LLUpdateChecker::check(std::string const & protocolVersion, std::string const & hostUrl,
+ std::string const & servicePath, std::string channel, std::string version)
+{}
+LLUpdateDownloader::LLUpdateDownloader(Client & ) {}
+void LLUpdateDownloader::download(LLURI const & , std::string const &, std::string const &, bool){}
+
+class LLDir_Mock : public LLDir
+{
+ void initAppDirs(const std::string &app_name,
+ const std::string& app_read_only_data_dir = "") {}
+ U32 countFilesInDir(const std::string &dirname, const std::string &mask)
+ {
+ return 0;
+ }
+
+ void getRandomFileInDir(const std::string &dirname,
+ const std::string &mask,
+ std::string &fname) {}
+ std::string getCurPath() { return ""; }
+ BOOL fileExists(const std::string &filename) const { return false; }
+ std::string getLLPluginLauncher() { return ""; }
+ std::string getLLPluginFilename(std::string base_name) { return ""; }
+
+} gDirUtil;
+LLDir* gDirUtilp = &gDirUtil;
+LLDir::LLDir() {}
+LLDir::~LLDir() {}
+S32 LLDir::deleteFilesInDir(const std::string &dirname,
+ const std::string &mask)
+{ return 0; }
+
+void LLDir::setChatLogsDir(const std::string &path){}
+void LLDir::setPerAccountChatLogsDir(const std::string &username){}
+void LLDir::setLindenUserDir(const std::string &username){}
+void LLDir::setSkinFolder(const std::string &skin_folder){}
+bool LLDir::setCacheDir(const std::string &path){ return true; }
+void LLDir::dumpCurrentDirectories() {}
+
+std::string LLDir::getExpandedFilename(ELLPath location,
+ const std::string &filename) const
+{
+ return "";
+}
+
+std::string LLUpdateDownloader::downloadMarkerPath(void)
+{
+ return "";
+}
+
+void LLUpdateDownloader::resume(void) {}
+void LLUpdateDownloader::cancel(void) {}
+void LLUpdateDownloader::setBandwidthLimit(U64 bytesPerSecond) {}
+
+int ll_install_update(std::string const &, std::string const &, bool, LLInstallScriptMode)
+{
+ return 0;
+}
+
+std::string const & ll_install_failed_marker_path()
+{
+ static std::string wubba;
+ return wubba;
+}
+
+/*
+#pragma warning(disable: 4273)
+llus_mock_llifstream::llus_mock_llifstream(const std::string& _Filename,
+ ios_base::openmode _Mode,
+ int _Prot) :
+ std::basic_istream<char,std::char_traits< char > >(NULL,true)
+{}
+
+llus_mock_llifstream::~llus_mock_llifstream() {}
+bool llus_mock_llifstream::is_open() const {return true;}
+void llus_mock_llifstream::close() {}
+*/
+
+/*****************************************************************************
+* TUT
+*****************************************************************************/
+namespace tut
+{
+ struct llupdaterservice_data
+ {
+ llupdaterservice_data() :
+ pumps(LLEventPumps::instance()),
+ test_url("dummy_url"),
+ test_channel("dummy_channel"),
+ test_version("dummy_version")
+ {}
+ LLEventPumps& pumps;
+ std::string test_url;
+ std::string test_channel;
+ std::string test_version;
+ };
+
+ typedef test_group<llupdaterservice_data> llupdaterservice_group;
+ typedef llupdaterservice_group::object llupdaterservice_object;
+ llupdaterservice_group llupdaterservicegrp("LLUpdaterService");
+
+ template<> template<>
+ void llupdaterservice_object::test<1>()
+ {
+ DEBUG;
+ LLUpdaterService updater;
+ bool got_usage_error = false;
+ try
+ {
+ updater.startChecking();
+ }
+ catch(LLUpdaterService::UsageError)
+ {
+ got_usage_error = true;
+ }
+ ensure("Caught start before params", got_usage_error);
+ }
+
+ template<> template<>
+ void llupdaterservice_object::test<2>()
+ {
+ DEBUG;
+ LLUpdaterService updater;
+ bool got_usage_error = false;
+ try
+ {
+ updater.initialize("1.0",test_url, "update" ,test_channel, test_version);
+ updater.startChecking();
+ updater.initialize("1.0", "other_url", "update", test_channel, test_version);
+ }
+ catch(LLUpdaterService::UsageError)
+ {
+ got_usage_error = true;
+ }
+ ensure("Caught params while running", got_usage_error);
+ }
+
+ template<> template<>
+ void llupdaterservice_object::test<3>()
+ {
+ DEBUG;
+ LLUpdaterService updater;
+ updater.initialize("1.0", test_url, "update", test_channel, test_version);
+ updater.startChecking();
+ ensure(updater.isChecking());
+ updater.stopChecking();
+ ensure(!updater.isChecking());
+ }
+}