summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.hgtags4
-rw-r--r--BuildParams6
-rw-r--r--doc/contributions.txt9
-rw-r--r--indra/CMakeLists.txt5
-rw-r--r--indra/cmake/00-Common.cmake4
-rw-r--r--indra/cmake/LLAddBuildTest.cmake538
-rw-r--r--indra/linux_updater/linux_updater.cpp178
-rw-r--r--indra/llaudio/llaudioengine.cpp4
-rw-r--r--indra/llcommon/CMakeLists.txt2
-rw-r--r--indra/llcommon/indra_constants.h11
-rw-r--r--indra/llcommon/llfile.cpp5
-rw-r--r--indra/llcommon/llthread.cpp30
-rw-r--r--indra/llcommon/llthreadsafequeue.cpp109
-rw-r--r--indra/llcommon/llthreadsafequeue.h205
-rw-r--r--indra/llcommon/llversionviewer.h2
-rw-r--r--indra/llinventory/llinventory.cpp2
-rw-r--r--indra/llmessage/llcachename.cpp54
-rw-r--r--indra/llui/llaccordionctrltab.cpp3
-rw-r--r--indra/llui/llbutton.cpp8
-rw-r--r--indra/llui/llbutton.h4
-rw-r--r--indra/llui/llcombobox.cpp2
-rw-r--r--indra/llui/lldockcontrol.cpp27
-rw-r--r--indra/llui/llfloater.cpp47
-rw-r--r--indra/llui/llfloater.h8
-rw-r--r--indra/llui/lliconctrl.cpp5
-rw-r--r--indra/llui/lliconctrl.h5
-rw-r--r--indra/llui/lllineeditor.cpp3
-rw-r--r--indra/llui/llmenubutton.cpp7
-rw-r--r--indra/llui/llmenubutton.h1
-rw-r--r--indra/llui/llpanel.cpp2
-rw-r--r--indra/llui/llscrollcontainer.cpp5
-rw-r--r--indra/llui/llscrolllistcolumn.cpp9
-rw-r--r--indra/llui/llscrolllistctrl.cpp3
-rw-r--r--indra/llui/lltextbase.cpp3
-rw-r--r--indra/llui/llui.cpp11
-rw-r--r--indra/llui/llui.h2
-rw-r--r--indra/llui/lluictrl.cpp33
-rw-r--r--indra/llui/lluictrl.h17
-rw-r--r--indra/llvfs/tests/lldir_test.cpp4
-rw-r--r--indra/llxml/llcontrol.cpp26
-rw-r--r--indra/mac_updater/mac_updater.cpp83
-rw-r--r--indra/newview/CMakeLists.txt24
-rw-r--r--indra/newview/app_settings/cmd_line.xml3
-rw-r--r--indra/newview/app_settings/settings.xml81
-rw-r--r--indra/newview/generate_breakpad_symbols.py11
-rw-r--r--indra/newview/installers/windows/installer_template.nsi55
-rw-r--r--indra/newview/llagent.cpp10
-rw-r--r--indra/newview/llagent.h1
-rw-r--r--indra/newview/llappviewer.cpp140
-rw-r--r--indra/newview/llappviewer.h12
-rw-r--r--indra/newview/llbottomtray.cpp21
-rw-r--r--indra/newview/llchiclet.cpp8
-rw-r--r--indra/newview/llcolorswatch.cpp32
-rw-r--r--indra/newview/llcurrencyuimanager.cpp4
-rw-r--r--indra/newview/llfloaterabout.cpp4
-rw-r--r--indra/newview/llfloatercolorpicker.cpp19
-rw-r--r--indra/newview/llfloatercolorpicker.h1
-rw-r--r--indra/newview/llfloaterevent.cpp5
-rw-r--r--indra/newview/llfloaterevent.h1
-rw-r--r--indra/newview/llfloatergroups.cpp5
-rw-r--r--indra/newview/llfloaterpostcard.cpp10
-rw-r--r--indra/newview/llfloaterpreference.cpp18
-rw-r--r--indra/newview/llfloaterpreference.h2
-rw-r--r--indra/newview/llfloatersnapshot.cpp15
-rw-r--r--indra/newview/llimview.cpp33
-rw-r--r--indra/newview/llinventorylistitem.cpp3
-rw-r--r--indra/newview/lllogchat.cpp46
-rw-r--r--indra/newview/lllogininstance.cpp6
-rw-r--r--indra/newview/llmainlooprepeater.cpp88
-rw-r--r--indra/newview/llmainlooprepeater.h65
-rw-r--r--indra/newview/llmoveview.cpp2
-rw-r--r--indra/newview/llnearbychat.cpp13
-rw-r--r--indra/newview/llnearbychat.h1
-rw-r--r--indra/newview/llpanelavatar.cpp22
-rw-r--r--indra/newview/llpanelavatar.h4
-rw-r--r--indra/newview/llpanellandmarks.cpp3
-rw-r--r--indra/newview/llpanellogin.cpp4
-rw-r--r--indra/newview/llpanelpeople.cpp39
-rw-r--r--indra/newview/llpanelpeople.h1
-rw-r--r--indra/newview/llpanelpick.cpp3
-rw-r--r--indra/newview/llpanelplaceinfo.cpp4
-rw-r--r--indra/newview/llpanelplaces.cpp16
-rw-r--r--indra/newview/llpanelplaces.h3
-rw-r--r--indra/newview/llpanelteleporthistory.cpp4
-rw-r--r--indra/newview/llremoteparcelrequest.cpp56
-rw-r--r--indra/newview/llremoteparcelrequest.h2
-rw-r--r--indra/newview/llscriptfloater.cpp46
-rw-r--r--indra/newview/llscriptfloater.h3
-rw-r--r--indra/newview/llsidepanelappearance.cpp9
-rw-r--r--indra/newview/llsidetray.cpp18
-rw-r--r--indra/newview/llsidetray.h29
-rw-r--r--indra/newview/llspeakbutton.cpp7
-rw-r--r--indra/newview/llspeakingindicatormanager.cpp5
-rw-r--r--indra/newview/llstartup.cpp13
-rw-r--r--indra/newview/llstartup.h1
-rw-r--r--indra/newview/lltexturectrl.cpp20
-rw-r--r--indra/newview/lltoastgroupnotifypanel.cpp2
-rw-r--r--indra/newview/lltoastnotifypanel.cpp17
-rw-r--r--indra/newview/lltoastscripttextbox.cpp109
-rw-r--r--indra/newview/lltoastscripttextbox.h58
-rw-r--r--indra/newview/lltransientfloatermgr.cpp5
-rw-r--r--indra/newview/lltranslate.cpp12
-rw-r--r--indra/newview/llversioninfo.cpp37
-rw-r--r--indra/newview/llversioninfo.h7
-rw-r--r--indra/newview/llviewercontrol.cpp15
-rw-r--r--indra/newview/llviewercontrol.h2
-rw-r--r--indra/newview/llviewermedia.cpp2
-rw-r--r--indra/newview/llviewermenu.cpp6
-rw-r--r--indra/newview/llviewermenufile.cpp2
-rw-r--r--indra/newview/llviewermessage.cpp23
-rw-r--r--indra/newview/llviewerstats.cpp3
-rw-r--r--indra/newview/llviewerwindow.cpp14
-rw-r--r--indra/newview/llvoavatar.cpp2
-rw-r--r--indra/newview/llvoavatarself.cpp15
-rw-r--r--indra/newview/skins/default/colors.xml3
-rw-r--r--indra/newview/skins/default/xui/da/floater_avatar_picker.xml8
-rw-r--r--indra/newview/skins/default/xui/da/floater_bumps.xml4
-rw-r--r--indra/newview/skins/default/xui/da/floater_buy_object.xml37
-rw-r--r--indra/newview/skins/default/xui/da/floater_display_name.xml18
-rw-r--r--indra/newview/skins/default/xui/da/floater_event.xml45
-rw-r--r--indra/newview/skins/default/xui/da/floater_incoming_call.xml2
-rw-r--r--indra/newview/skins/default/xui/da/floater_pay.xml2
-rw-r--r--indra/newview/skins/default/xui/da/floater_tools.xml4
-rw-r--r--indra/newview/skins/default/xui/da/floater_voice_controls.xml4
-rw-r--r--indra/newview/skins/default/xui/da/inspect_avatar.xml5
-rw-r--r--indra/newview/skins/default/xui/da/menu_viewer.xml6
-rw-r--r--indra/newview/skins/default/xui/da/notifications.xml148
-rw-r--r--indra/newview/skins/default/xui/da/panel_edit_profile.xml10
-rw-r--r--indra/newview/skins/default/xui/da/panel_group_land_money.xml1
-rw-r--r--indra/newview/skins/default/xui/da/panel_login.xml4
-rw-r--r--indra/newview/skins/default/xui/da/panel_place_profile.xml3
-rw-r--r--indra/newview/skins/default/xui/da/panel_places.xml2
-rw-r--r--indra/newview/skins/default/xui/da/panel_preferences_general.xml8
-rw-r--r--indra/newview/skins/default/xui/da/panel_preferences_setup.xml10
-rw-r--r--indra/newview/skins/default/xui/da/panel_profile.xml2
-rw-r--r--indra/newview/skins/default/xui/da/panel_profile_view.xml8
-rw-r--r--indra/newview/skins/default/xui/da/role_actions.xml91
-rw-r--r--indra/newview/skins/default/xui/da/strings.xml22
-rw-r--r--indra/newview/skins/default/xui/de/panel_places.xml2
-rw-r--r--indra/newview/skins/default/xui/de/panel_profile.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_buy_currency.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_nearby_chat.xml3
-rw-r--r--indra/newview/skins/default/xui/en/floater_preferences.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_tools.xml16
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml88
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml26
-rw-r--r--indra/newview/skins/default/xui/en/panel_avatar_list_item.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_classified_info.xml3
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_alpha.xml24
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_classified.xml3
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_pick.xml3
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_tattoo.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_wearable.xml3
-rw-r--r--indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml3
-rw-r--r--indra/newview/skins/default/xui/en/panel_landmark_info.xml3
-rw-r--r--indra/newview/skins/default/xui/en/panel_landmarks.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_main_inventory.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_notify_textbox.xml68
-rw-r--r--indra/newview/skins/default/xui/en/panel_outfit_edit.xml3
-rw-r--r--indra/newview/skins/default/xui/en/panel_people.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_pick_info.xml3
-rw-r--r--indra/newview/skins/default/xui/en/panel_place_profile.xml3
-rw-r--r--indra/newview/skins/default/xui/en/panel_places.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_colors.xml18
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_general.xml9
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_privacy.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_setup.xml16
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_sound.xml55
-rw-r--r--indra/newview/skins/default/xui/en/panel_profile.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_profile_view.xml3
-rw-r--r--indra/newview/skins/default/xui/en/sidepanel_item_info.xml3
-rw-r--r--indra/newview/skins/default/xui/en/sidepanel_task_info.xml3
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml4
-rw-r--r--indra/newview/skins/default/xui/en/widgets/avatar_icon.xml4
-rw-r--r--indra/newview/skins/default/xui/en/widgets/button.xml3
-rw-r--r--indra/newview/skins/default/xui/en/widgets/icon.xml1
-rw-r--r--indra/newview/skins/default/xui/es/panel_places.xml2
-rw-r--r--indra/newview/skins/default/xui/es/panel_profile.xml2
-rw-r--r--indra/newview/skins/default/xui/fr/panel_places.xml2
-rw-r--r--indra/newview/skins/default/xui/fr/panel_profile.xml2
-rw-r--r--indra/newview/skins/default/xui/it/floater_tools.xml2
-rw-r--r--indra/newview/skins/default/xui/it/panel_places.xml2
-rw-r--r--indra/newview/skins/default/xui/it/panel_profile.xml2
-rw-r--r--indra/newview/skins/default/xui/ja/panel_places.xml2
-rw-r--r--indra/newview/skins/default/xui/ja/panel_profile.xml2
-rw-r--r--indra/newview/skins/default/xui/nl/floater_tools.xml12
-rw-r--r--indra/newview/skins/default/xui/pl/floater_tools.xml2
-rw-r--r--indra/newview/skins/default/xui/pl/panel_places.xml2
-rw-r--r--indra/newview/skins/default/xui/pl/panel_profile.xml2
-rw-r--r--indra/newview/skins/default/xui/pl/strings.xml2
-rw-r--r--indra/newview/skins/default/xui/pt/floater_tools.xml2
-rw-r--r--indra/newview/skins/default/xui/pt/panel_places.xml2
-rw-r--r--indra/newview/skins/default/xui/pt/panel_profile.xml2
-rw-r--r--indra/newview/tests/lllogininstance_test.cpp9
-rw-r--r--indra/newview/tests/llremoteparcelrequest_test.cpp134
-rw-r--r--indra/newview/tests/llversioninfo_test.cpp114
-rw-r--r--indra/newview/tests/llviewerhelputil_test.cpp17
-rw-r--r--indra/newview/viewer_manifest.py27
-rw-r--r--indra/viewer_components/CMakeLists.txt2
-rw-r--r--indra/viewer_components/updater/CMakeLists.txt82
-rw-r--r--indra/viewer_components/updater/llupdatechecker.cpp194
-rw-r--r--indra/viewer_components/updater/llupdatechecker.h82
-rw-r--r--indra/viewer_components/updater/llupdatedownloader.cpp428
-rw-r--r--indra/viewer_components/updater/llupdatedownloader.h87
-rw-r--r--indra/viewer_components/updater/llupdateinstaller.cpp90
-rw-r--r--indra/viewer_components/updater/llupdateinstaller.h57
-rw-r--r--indra/viewer_components/updater/llupdaterservice.cpp519
-rw-r--r--indra/viewer_components/updater/llupdaterservice.h85
-rw-r--r--indra/viewer_components/updater/scripts/darwin/update_install9
-rw-r--r--indra/viewer_components/updater/scripts/linux/update_install10
-rw-r--r--indra/viewer_components/updater/scripts/windows/update_install.bat3
-rw-r--r--indra/viewer_components/updater/tests/llupdaterservice_test.cpp199
-rwxr-xr-x[-rw-r--r--]scripts/md5check.py0
214 files changed, 4850 insertions, 1060 deletions
diff --git a/.hgtags b/.hgtags
index 5bc619156a..1289dfdf24 100644
--- a/.hgtags
+++ b/.hgtags
@@ -36,3 +36,7 @@ a3c12342b1af0951b8aa3b828aacef17fcea8178 2.3.0-beta1
db0fe9bb65187f365e58a717dd23d0f4754a9c1d 2.3.0-beta2
6ad3d6fa35a4e320e9ce442fce2bf9c7fc852556 2.3.0-beta3
6ad3d6fa35a4e320e9ce442fce2bf9c7fc852556 2.3.0-release
+dbc206fc61d89ff4cfe15aade0bf0c7bc7fee1c9 2.4.0-start
+dc6483491b4af559060bccaef8e9045a303212dd 2.4.0-beta1
+dc6483491b4af559060bccaef8e9045a303212dd 2.4.0-beta1
+3bc1f50a72e117f4d4ad8d555f0c785ea8cc201e 2.4.0-beta1
diff --git a/BuildParams b/BuildParams
index abeaebae98..8e4164d5ca 100644
--- a/BuildParams
+++ b/BuildParams
@@ -14,6 +14,9 @@ public_build = true
# Update Public Inworld Build Status Indicators
email_status_this_is_os = true
+# Limit extent of codeticket updates to revisions after...
+codeticket_since = 2.2.0-release
+
# ========================================
# Viewer Development
# ========================================
@@ -43,6 +46,9 @@ viewer-beta.viewer_channel = "Second Life Beta Viewer"
viewer-beta.login_channel = "Second Life Beta Viewer"
viewer-beta.build_debug_release_separately = true
viewer-beta.build_viewer_update_version_manager = true
+# Settings to test new code ticket service
+viewer-beta.codeticket_server_url = "http://pdp75.lindenlab.com:8000/codeticket/linden/"
+viewer-beta.codeticket_add_context = true
# ========================================
# Viewer Release
diff --git a/doc/contributions.txt b/doc/contributions.txt
index b255ca98cd..2334aeb17b 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -355,6 +355,9 @@ Joghert LeSabre
VWR-64
Jonathan Yap
VWR-17801
+ STORM-616
+ STORM-679
+ STORM-596
Kage Pixel
VWR-11
Ken March
@@ -767,16 +770,16 @@ WolfPup Lowenhar
STORM-102
STORM-103
STORM-143
+ STORM-255
+ STORM-256
STORM-535
STORM-544
STORM-654
+ STORM-674
VWR-20741
VWR-20933
Zai Lynch
VWR-19505
-Wolfpup Lowenhar
- STORM-255
- STORM-256
Zarkonnen Decosta
VWR-253
Zi Ree
diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt
index 8d4969a49e..d01e1869b6 100644
--- a/indra/CMakeLists.txt
+++ b/indra/CMakeLists.txt
@@ -22,7 +22,10 @@ set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
include(Variables)
if (DARWIN)
- cmake_minimum_required(VERSION 2.6.2 FATAL_ERROR)
+ # 2.6.4 fixes a Mac bug in get_target_property(... "SLPlugin" LOCATION):
+ # before that version it returns "pathname/SLPlugin", whereas the correct
+ # answer is "pathname/SLPlugin.app/Contents/MacOS/SLPlugin".
+ cmake_minimum_required(VERSION 2.6.4 FATAL_ERROR)
endif (DARWIN)
if (NOT CMAKE_BUILD_TYPE)
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index a114d6e778..db2cdb5ff8 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -38,10 +38,10 @@ if (WINDOWS)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd /MP"
CACHE STRING "C++ compiler debug options" FORCE)
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
- "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP"
+ "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP /Ob2"
CACHE STRING "C++ compiler release-with-debug options" FORCE)
set(CMAKE_CXX_FLAGS_RELEASE
- "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP"
+ "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP /Ob2"
CACHE STRING "C++ compiler release options" FORCE)
set(CMAKE_CXX_STANDARD_LIBRARIES "")
diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake
index 79c3bb7da2..29e2492551 100644
--- a/indra/cmake/LLAddBuildTest.cmake
+++ b/indra/cmake/LLAddBuildTest.cmake
@@ -1,265 +1,273 @@
-# -*- 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} )
-
- #
- # 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}")
-
- # 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}")
+
+ # 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/linux_updater/linux_updater.cpp b/indra/linux_updater/linux_updater.cpp
index 23c34e52e7..d909516bf8 100644
--- a/indra/linux_updater/linux_updater.cpp
+++ b/indra/linux_updater/linux_updater.cpp
@@ -49,6 +49,7 @@ const guint ROTATE_IMAGE_TIMEOUT = 8000;
typedef struct _updater_app_state {
std::string app_name;
std::string url;
+ std::string file;
std::string image_dir;
std::string dest_dir;
std::string strings_dirs;
@@ -113,7 +114,7 @@ BOOL install_package(std::string package_file, std::string destination);
BOOL spawn_viewer(UpdaterAppState *app_state);
extern "C" {
- void on_window_closed(GtkWidget *sender, gpointer state);
+ void on_window_closed(GtkWidget *sender, GdkEvent *event, gpointer state);
gpointer worker_thread_cb(gpointer *data);
int download_progress_cb(gpointer data, double t, double d, double utotal, double ulnow);
gboolean rotate_image_cb(gpointer data);
@@ -220,7 +221,7 @@ std::string next_image_filename(std::string& image_path)
return image_path + "/" + image_filename;
}
-void on_window_closed(GtkWidget *sender, gpointer data)
+void on_window_closed(GtkWidget *sender, GdkEvent* event, gpointer data)
{
UpdaterAppState *app_state;
@@ -266,85 +267,95 @@ gpointer worker_thread_cb(gpointer data)
CURLcode result;
FILE *package_file;
GError *error = NULL;
- char *tmp_filename = NULL;
int fd;
//g_return_val_if_fail (data != NULL, NULL);
app_state = (UpdaterAppState *) data;
try {
- // create temporary file to store the package.
- fd = g_file_open_tmp
- ("secondlife-update-XXXXXX", &tmp_filename, &error);
- if (error != NULL)
- {
- llerrs << "Unable to create temporary file: "
- << error->message
- << llendl;
-
- g_error_free(error);
- throw 0;
- }
- package_file = fdopen(fd, "wb");
- if (package_file == NULL)
+ if(!app_state->url.empty())
{
- llerrs << "Failed to create temporary file: "
- << tmp_filename
- << llendl;
+ char* tmp_local_filename = NULL;
+ // create temporary file to store the package.
+ fd = g_file_open_tmp
+ ("secondlife-update-XXXXXX", &tmp_local_filename, &error);
+ if (error != NULL)
+ {
+ llerrs << "Unable to create temporary file: "
+ << error->message
+ << llendl;
- gdk_threads_enter();
- display_error(app_state->window,
- LLTrans::getString("UpdaterFailDownloadTitle"),
- LLTrans::getString("UpdaterFailUpdateDescriptive"));
- gdk_threads_leave();
- throw 0;
- }
+ g_error_free(error);
+ throw 0;
+ }
+
+ if(tmp_local_filename != NULL)
+ {
+ app_state->file = tmp_local_filename;
+ g_free(tmp_local_filename);
+ }
- // initialize curl and start downloading the package
- llinfos << "Downloading package: " << app_state->url << llendl;
+ package_file = fdopen(fd, "wb");
+ if (package_file == NULL)
+ {
+ llerrs << "Failed to create temporary file: "
+ << app_state->file.c_str()
+ << llendl;
+
+ gdk_threads_enter();
+ display_error(app_state->window,
+ LLTrans::getString("UpdaterFailDownloadTitle"),
+ LLTrans::getString("UpdaterFailUpdateDescriptive"));
+ gdk_threads_leave();
+ throw 0;
+ }
- curl = curl_easy_init();
- if (curl == NULL)
- {
- llerrs << "Failed to initialize libcurl" << llendl;
+ // initialize curl and start downloading the package
+ llinfos << "Downloading package: " << app_state->url << llendl;
- gdk_threads_enter();
- display_error(app_state->window,
- LLTrans::getString("UpdaterFailDownloadTitle"),
- LLTrans::getString("UpdaterFailUpdateDescriptive"));
- gdk_threads_leave();
- throw 0;
- }
+ curl = curl_easy_init();
+ if (curl == NULL)
+ {
+ llerrs << "Failed to initialize libcurl" << llendl;
+
+ gdk_threads_enter();
+ display_error(app_state->window,
+ LLTrans::getString("UpdaterFailDownloadTitle"),
+ LLTrans::getString("UpdaterFailUpdateDescriptive"));
+ gdk_threads_leave();
+ throw 0;
+ }
- curl_easy_setopt(curl, CURLOPT_URL, app_state->url.c_str());
- curl_easy_setopt(curl, CURLOPT_NOSIGNAL, TRUE);
- curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, TRUE);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, package_file);
- curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE);
- curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION,
- &download_progress_cb);
- curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, app_state);
+ curl_easy_setopt(curl, CURLOPT_URL, app_state->url.c_str());
+ curl_easy_setopt(curl, CURLOPT_NOSIGNAL, TRUE);
+ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, TRUE);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, package_file);
+ curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE);
+ curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION,
+ &download_progress_cb);
+ curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, app_state);
- result = curl_easy_perform(curl);
- fclose(package_file);
- curl_easy_cleanup(curl);
+ result = curl_easy_perform(curl);
+ fclose(package_file);
+ curl_easy_cleanup(curl);
- if (result)
- {
- llerrs << "Failed to download update: "
- << app_state->url
- << llendl;
+ if (result)
+ {
+ llerrs << "Failed to download update: "
+ << app_state->url
+ << llendl;
- gdk_threads_enter();
- display_error(app_state->window,
- LLTrans::getString("UpdaterFailDownloadTitle"),
- LLTrans::getString("UpdaterFailUpdateDescriptive"));
- gdk_threads_leave();
+ gdk_threads_enter();
+ display_error(app_state->window,
+ LLTrans::getString("UpdaterFailDownloadTitle"),
+ LLTrans::getString("UpdaterFailUpdateDescriptive"));
+ gdk_threads_leave();
- throw 0;
+ throw 0;
+ }
}
-
+
// now pulse the progres bar back and forth while the package is
// being unpacked
gdk_threads_enter();
@@ -357,7 +368,7 @@ gpointer worker_thread_cb(gpointer data)
// *TODO: if the destination is not writable, terminate this
// thread and show file chooser?
- if (!install_package(tmp_filename, app_state->dest_dir))
+ if (!install_package(app_state->file.c_str(), app_state->dest_dir))
{
llwarns << "Failed to install package to destination: "
<< app_state->dest_dir
@@ -392,15 +403,6 @@ gpointer worker_thread_cb(gpointer data)
app_state->failure = TRUE;
}
- // FIXME: delete package file also if delete-event is raised on window
- if (tmp_filename != NULL)
- {
- if (gDirUtilp->fileExists(tmp_filename))
- {
- LLFile::remove(tmp_filename);
- }
- }
-
gdk_threads_enter();
updater_app_quit(app_state);
gdk_threads_leave();
@@ -712,7 +714,7 @@ BOOL spawn_viewer(UpdaterAppState *app_state)
void show_usage_and_exit()
{
- std::cout << "Usage: linux-updater --url URL --name NAME --dest PATH --stringsdir PATH1,PATH2 --stringsfile FILE"
+ std::cout << "Usage: linux-updater <--url URL | --file FILE> --name NAME --dest PATH --stringsdir PATH1,PATH2 --stringsfile FILE"
<< "[--image-dir PATH]"
<< std::endl;
exit(1);
@@ -728,6 +730,10 @@ void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state)
{
app_state->url = argv[i];
}
+ else if ((!strcmp(argv[i], "--file")) && (++i < argc))
+ {
+ app_state->file = argv[i];
+ }
else if ((!strcmp(argv[i], "--name")) && (++i < argc))
{
app_state->app_name = argv[i];
@@ -756,7 +762,7 @@ void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state)
}
if (app_state->app_name.empty()
- || app_state->url.empty()
+ || (app_state->url.empty() && app_state->file.empty())
|| app_state->dest_dir.empty())
{
show_usage_and_exit();
@@ -771,10 +777,10 @@ void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state)
int main(int argc, char **argv)
{
- UpdaterAppState app_state;
+ UpdaterAppState* app_state = new UpdaterAppState;
GThread *worker_thread;
- parse_args_and_init(argc, argv, &app_state);
+ parse_args_and_init(argc, argv, app_state);
// Initialize logger, and rename old log file
gDirUtilp->initAppDirs("SecondLife");
@@ -797,17 +803,29 @@ int main(int argc, char **argv)
gtk_init(&argc, &argv);
// create UI
- updater_app_ui_init(&app_state);
+ updater_app_ui_init(app_state);
//llinfos << "SAMPLE TRANSLATION IS: " << LLTrans::getString("LoginInProgress") << llendl;
// create download thread
worker_thread = g_thread_create
- (GThreadFunc(worker_thread_cb), &app_state, FALSE, NULL);
+ (GThreadFunc(worker_thread_cb), app_state, FALSE, NULL);
gdk_threads_enter();
gtk_main();
gdk_threads_leave();
- return (app_state.failure == FALSE) ? 0 : 1;
+ // Delete the file only if created from url download.
+ if(!app_state->url.empty() && !app_state->file.empty())
+ {
+ if (gDirUtilp->fileExists(app_state->file))
+ {
+ LLFile::remove(app_state->file);
+ }
+ }
+
+ bool success = !app_state->failure;
+ delete app_state;
+ return success ? 0 : 1;
}
+
diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp
index 1cc03bddb8..c9cb1cd6e7 100644
--- a/indra/llaudio/llaudioengine.cpp
+++ b/indra/llaudio/llaudioengine.cpp
@@ -1557,6 +1557,10 @@ bool LLAudioSource::hasPendingPreloads() const
LLAudioData *adp = iter->second;
// note: a bad UUID will forever be !hasDecodedData()
// but also !hasValidData(), hence the check for hasValidData()
+ if (!adp)
+ {
+ continue;
+ }
if (!adp->hasDecodedData() && adp->hasValidData())
{
// This source is still waiting for a preload
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 478f2fedbd..9342a22d46 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -93,6 +93,7 @@ set(llcommon_SOURCE_FILES
llstringtable.cpp
llsys.cpp
llthread.cpp
+ llthreadsafequeue.cpp
lltimer.cpp
lluri.cpp
lluuid.cpp
@@ -225,6 +226,7 @@ set(llcommon_HEADER_FILES
llstringtable.h
llsys.h
llthread.h
+ llthreadsafequeue.h
lltimer.h
lltreeiterators.h
lluri.h
diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h
index b0618bfe59..95cb606240 100644
--- a/indra/llcommon/indra_constants.h
+++ b/indra/llcommon/indra_constants.h
@@ -245,9 +245,6 @@ const U8 SIM_ACCESS_ADULT = 42; // Seriously Adult Only
const U8 SIM_ACCESS_DOWN = 254;
const U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT;
-// group constants
-const S32 MAX_AGENT_GROUPS = 25;
-
// attachment constants
const S32 MAX_AGENT_ATTACHMENTS = 38;
const U8 ATTACHMENT_ADD = 0x80;
@@ -300,6 +297,14 @@ const U32 START_LOCATION_ID_COUNT = 6;
// group constants
const U32 GROUP_MIN_SIZE = 2;
+// gMaxAgentGroups is now sent by login.cgi, which
+// looks it up from globals.xml.
+//
+// For now we need an old default value however,
+// so the viewer can be deployed ahead of login.cgi.
+//
+const S32 DEFAULT_MAX_AGENT_GROUPS = 25;
+
// radius within which a chat message is fully audible
const F32 CHAT_WHISPER_RADIUS = 10.f;
const F32 CHAT_NORMAL_RADIUS = 20.f;
diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp
index 694c90e184..c32a776c3f 100644
--- a/indra/llcommon/llfile.cpp
+++ b/indra/llcommon/llfile.cpp
@@ -329,7 +329,12 @@ void llofstream::close()
if(is_open())
{
if (_Filebuffer->close() == 0)
+ {
_Myios::setstate(ios_base::failbit); /*Flawfinder: ignore*/
+ }
+ delete _Filebuffer;
+ _Filebuffer = NULL;
+ _ShouldClose = false;
}
}
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index d7b7c3699c..49d05ef411 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -63,9 +63,6 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
{
LLThread *threadp = (LLThread *)datap;
- // Set thread state to running
- threadp->mStatus = RUNNING;
-
// Run the user supplied function
threadp->run();
@@ -147,26 +144,45 @@ void LLThread::shutdown()
{
// This thread just wouldn't stop, even though we gave it time
llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl;
+ // Put a stake in its heart.
+ apr_thread_exit(mAPRThreadp, -1);
return;
}
mAPRThreadp = NULL;
}
delete mRunCondition;
+ mRunCondition = 0;
- if (mIsLocalPool)
+ if (mIsLocalPool && mAPRPoolp)
{
apr_pool_destroy(mAPRPoolp);
+ mAPRPoolp = 0;
}
}
void LLThread::start()
{
- apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp);
+ llassert(isStopped());
+
+ // Set thread state to running
+ mStatus = RUNNING;
- // We won't bother joining
- apr_thread_detach(mAPRThreadp);
+ apr_status_t status =
+ apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp);
+
+ if(status == APR_SUCCESS)
+ {
+ // We won't bother joining
+ apr_thread_detach(mAPRThreadp);
+ }
+ else
+ {
+ mStatus = STOPPED;
+ llwarns << "failed to start thread " << mName << llendl;
+ ll_apr_warn_status(status);
+ }
}
//============================================================================
diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp
new file mode 100644
index 0000000000..8a73e632a9
--- /dev/null
+++ b/indra/llcommon/llthreadsafequeue.cpp
@@ -0,0 +1,109 @@
+/**
+ * @file llthread.cpp
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+#include <apr_pools.h>
+#include <apr_queue.h>
+#include "llthreadsafequeue.h"
+
+
+
+// LLThreadSafeQueueImplementation
+//-----------------------------------------------------------------------------
+
+
+LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity):
+ mOwnsPool(pool == 0),
+ mPool(pool),
+ mQueue(0)
+{
+ if(mOwnsPool) {
+ apr_status_t status = apr_pool_create(&mPool, 0);
+ if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate pool");
+ } else {
+ ; // No op.
+ }
+
+ apr_status_t status = apr_queue_create(&mQueue, capacity, mPool);
+ if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate queue");
+}
+
+
+LLThreadSafeQueueImplementation::~LLThreadSafeQueueImplementation()
+{
+ if(mQueue != 0) {
+ if(apr_queue_size(mQueue) != 0) llwarns <<
+ "terminating queue which still contains " << apr_queue_size(mQueue) <<
+ " elements;" << "memory will be leaked" << LL_ENDL;
+ apr_queue_term(mQueue);
+ }
+ if(mOwnsPool && (mPool != 0)) apr_pool_destroy(mPool);
+}
+
+
+void LLThreadSafeQueueImplementation::pushFront(void * element)
+{
+ apr_status_t status = apr_queue_push(mQueue, element);
+
+ if(status == APR_EINTR) {
+ throw LLThreadSafeQueueInterrupt();
+ } else if(status != APR_SUCCESS) {
+ throw LLThreadSafeQueueError("push failed");
+ } else {
+ ; // Success.
+ }
+}
+
+
+bool LLThreadSafeQueueImplementation::tryPushFront(void * element){
+ return apr_queue_trypush(mQueue, element) == APR_SUCCESS;
+}
+
+
+void * LLThreadSafeQueueImplementation::popBack(void)
+{
+ void * element;
+ apr_status_t status = apr_queue_pop(mQueue, &element);
+
+ if(status == APR_EINTR) {
+ throw LLThreadSafeQueueInterrupt();
+ } else if(status != APR_SUCCESS) {
+ throw LLThreadSafeQueueError("pop failed");
+ } else {
+ return element;
+ }
+}
+
+
+bool LLThreadSafeQueueImplementation::tryPopBack(void *& element)
+{
+ return apr_queue_trypop(mQueue, &element) == APR_SUCCESS;
+}
+
+
+size_t LLThreadSafeQueueImplementation::size()
+{
+ return apr_queue_size(mQueue);
+}
diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
new file mode 100644
index 0000000000..58cac38769
--- /dev/null
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -0,0 +1,205 @@
+/**
+ * @file llthreadsafequeue.h
+ * @brief Base classes for thread, mutex and condition handling.
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLTHREADSAFEQUEUE_H
+#define LL_LLTHREADSAFEQUEUE_H
+
+
+#include <string>
+#include <stdexcept>
+
+
+struct apr_pool_t; // From apr_pools.h
+class LLThreadSafeQueueImplementation; // See below.
+
+
+//
+// A general queue exception.
+//
+class LL_COMMON_API LLThreadSafeQueueError:
+public std::runtime_error
+{
+public:
+ LLThreadSafeQueueError(std::string const & message):
+ std::runtime_error(message)
+ {
+ ; // No op.
+ }
+};
+
+
+//
+// An exception raised when blocking operations are interrupted.
+//
+class LL_COMMON_API LLThreadSafeQueueInterrupt:
+ public LLThreadSafeQueueError
+{
+public:
+ LLThreadSafeQueueInterrupt(void):
+ LLThreadSafeQueueError("queue operation interrupted")
+ {
+ ; // No op.
+ }
+};
+
+
+struct apr_queue_t; // From apr_queue.h
+
+
+//
+// Implementation details.
+//
+class LL_COMMON_API LLThreadSafeQueueImplementation
+{
+public:
+ LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity);
+ ~LLThreadSafeQueueImplementation();
+ void pushFront(void * element);
+ bool tryPushFront(void * element);
+ void * popBack(void);
+ bool tryPopBack(void *& element);
+ size_t size();
+
+private:
+ bool mOwnsPool;
+ apr_pool_t * mPool;
+ apr_queue_t * mQueue;
+};
+
+
+//
+// Implements a thread safe FIFO.
+//
+template<typename ElementT>
+class LLThreadSafeQueue
+{
+public:
+ typedef ElementT value_type;
+
+ // If the pool is set to NULL one will be allocated and managed by this
+ // queue.
+ LLThreadSafeQueue(apr_pool_t * pool = 0, unsigned int capacity = 1024);
+
+ // Add an element to the front of queue (will block if the queue has
+ // reached capacity).
+ //
+ // This call will raise an interrupt error if the queue is deleted while
+ // the caller is blocked.
+ void pushFront(ElementT const & element);
+
+ // Try to add an element to the front ofqueue without blocking. Returns
+ // true only if the element was actually added.
+ bool tryPushFront(ElementT const & element);
+
+ // Pop the element at the end of the queue (will block if the queue is
+ // empty).
+ //
+ // This call will raise an interrupt error if the queue is deleted while
+ // the caller is blocked.
+ ElementT popBack(void);
+
+ // Pop an element from the end of the queue if there is one available.
+ // Returns true only if an element was popped.
+ bool tryPopBack(ElementT & element);
+
+ // Returns the size of the queue.
+ size_t size();
+
+private:
+ LLThreadSafeQueueImplementation mImplementation;
+};
+
+
+
+// LLThreadSafeQueue
+//-----------------------------------------------------------------------------
+
+
+template<typename ElementT>
+LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(apr_pool_t * pool, unsigned int capacity):
+ mImplementation(pool, capacity)
+{
+ ; // No op.
+}
+
+
+template<typename ElementT>
+void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element)
+{
+ ElementT * elementCopy = new ElementT(element);
+ try {
+ mImplementation.pushFront(elementCopy);
+ } catch (LLThreadSafeQueueInterrupt) {
+ delete elementCopy;
+ throw;
+ }
+}
+
+
+template<typename ElementT>
+bool LLThreadSafeQueue<ElementT>::tryPushFront(ElementT const & element)
+{
+ ElementT * elementCopy = new ElementT(element);
+ bool result = mImplementation.tryPushFront(elementCopy);
+ if(!result) delete elementCopy;
+ return result;
+}
+
+
+template<typename ElementT>
+ElementT LLThreadSafeQueue<ElementT>::popBack(void)
+{
+ ElementT * element = reinterpret_cast<ElementT *> (mImplementation.popBack());
+ ElementT result(*element);
+ delete element;
+ return result;
+}
+
+
+template<typename ElementT>
+bool LLThreadSafeQueue<ElementT>::tryPopBack(ElementT & element)
+{
+ void * storedElement;
+ bool result = mImplementation.tryPopBack(storedElement);
+ if(result) {
+ ElementT * elementPtr = reinterpret_cast<ElementT *>(storedElement);
+ element = *elementPtr;
+ delete elementPtr;
+ } else {
+ ; // No op.
+ }
+ return result;
+}
+
+
+template<typename ElementT>
+size_t LLThreadSafeQueue<ElementT>::size(void)
+{
+ return mImplementation.size();
+}
+
+
+#endif
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
index b209e4aa38..d6fa5b1997 100644
--- a/indra/llcommon/llversionviewer.h
+++ b/indra/llcommon/llversionviewer.h
@@ -28,7 +28,7 @@
#define LL_LLVERSIONVIEWER_H
const S32 LL_VERSION_MAJOR = 2;
-const S32 LL_VERSION_MINOR = 4;
+const S32 LL_VERSION_MINOR = 5;
const S32 LL_VERSION_PATCH = 0;
const S32 LL_VERSION_BUILD = 0;
diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
index bda76eac80..a3caf79519 100644
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -61,8 +61,6 @@ static const std::string INV_FOLDER_ID_LABEL_WS("category_id");
///----------------------------------------------------------------------------
/// Local function declarations, constants, enums, and typedefs
///----------------------------------------------------------------------------
-const U8 TASK_INVENTORY_ITEM_KEY = 0;
-const U8 TASK_INVENTORY_ASSET_KEY = 1;
const LLUUID MAGIC_ID("3c115e51-04f4-523c-9fa6-98aff1034730");
diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp
index 4ab6bd2438..479efabb5f 100644
--- a/indra/llmessage/llcachename.cpp
+++ b/indra/llmessage/llcachename.cpp
@@ -556,35 +556,43 @@ std::string LLCacheName::buildUsername(const std::string& full_name)
//static
std::string LLCacheName::buildLegacyName(const std::string& complete_name)
{
- // regexp doesn't play nice with unicode, chop off the display name
+ //boost::regexp was showing up in the crashreporter, so doing
+ //painfully manual parsing using substr. LF
S32 open_paren = complete_name.rfind(" (");
+ S32 close_paren = complete_name.rfind(')');
- if (open_paren == std::string::npos)
+ if (open_paren != std::string::npos &&
+ close_paren == complete_name.length()-1)
{
- return complete_name;
- }
+ S32 length = close_paren - open_paren - 2;
+ std::string legacy_name = complete_name.substr(open_paren+2, length);
+
+ if (legacy_name.length() > 0)
+ {
+ std::string cap_letter = legacy_name.substr(0, 1);
+ LLStringUtil::toUpper(cap_letter);
+ legacy_name = cap_letter + legacy_name.substr(1);
+
+ S32 separator = legacy_name.find('.');
- std::string username = complete_name.substr(open_paren);
- boost::regex complete_name_regex("( \\()([a-z0-9]+)(.[a-z]+)*(\\))");
- boost::match_results<std::string::const_iterator> name_results;
- if (!boost::regex_match(username, name_results, complete_name_regex)) return complete_name;
+ if (separator != std::string::npos)
+ {
+ std::string last_name = legacy_name.substr(separator+1);
+ legacy_name = legacy_name.substr(0, separator);
- std::string legacy_name = name_results[2];
- // capitalize the first letter
- std::string cap_letter = legacy_name.substr(0, 1);
- LLStringUtil::toUpper(cap_letter);
- legacy_name = cap_letter + legacy_name.substr(1);
+ if (last_name.length() > 0)
+ {
+ cap_letter = last_name.substr(0, 1);
+ LLStringUtil::toUpper(cap_letter);
+ legacy_name = legacy_name + " " + cap_letter + last_name.substr(1);
+ }
+ }
- if (name_results[3].matched)
- {
- std::string last_name = name_results[3];
- std::string cap_letter = last_name.substr(1, 1);
- LLStringUtil::toUpper(cap_letter);
- last_name = cap_letter + last_name.substr(2);
- legacy_name = legacy_name + " " + last_name;
+ return legacy_name;
+ }
}
- return legacy_name;
+ return complete_name;
}
// This is a little bit kludgy. LLCacheNameCallback is a slot instead of a function pointer.
@@ -967,6 +975,10 @@ void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool isGroup)
if (entry->mLastName.empty())
{
full_name = cleanFullName(entry->mFirstName);
+
+ //fix what we are putting in the cache
+ entry->mFirstName = full_name;
+ entry->mLastName = "Resident";
}
else
{
diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp
index 9d49c1a831..9e4849c58b 100644
--- a/indra/llui/llaccordionctrltab.cpp
+++ b/indra/llui/llaccordionctrltab.cpp
@@ -203,7 +203,8 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw()
S32 width = getRect().getWidth();
S32 height = getRect().getHeight();
- gl_rect_2d(0,0,width - 1 ,height - 1,mHeaderBGColor.get(),true);
+ F32 alpha = getCurrentTransparency();
+ gl_rect_2d(0,0,width - 1 ,height - 1,mHeaderBGColor.get() % alpha,true);
LLAccordionCtrlTab* parent = dynamic_cast<LLAccordionCtrlTab*>(getParent());
bool collapsible = (parent && parent->getCollapsible());
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 65ef3e5f8f..45ceaff696 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -98,7 +98,8 @@ LLButton::Params::Params()
is_toggle("is_toggle", false),
scale_image("scale_image", true),
hover_glow_amount("hover_glow_amount"),
- commit_on_return("commit_on_return", true)
+ commit_on_return("commit_on_return", true),
+ use_draw_context_alpha("use_draw_context_alpha", true)
{
addSynonym(is_toggle, "toggle");
held_down_delay.seconds = 0.5f;
@@ -158,7 +159,8 @@ LLButton::LLButton(const LLButton::Params& p)
mLastDrawCharsCount(0),
mMouseDownSignal(NULL),
mMouseUpSignal(NULL),
- mHeldDownSignal(NULL)
+ mHeldDownSignal(NULL),
+ mUseDrawContextAlpha(p.use_draw_context_alpha)
{
static LLUICachedControl<S32> llbutton_orig_h_pad ("UIButtonOrigHPad", 0);
@@ -539,7 +541,7 @@ BOOL LLButton::handleHover(S32 x, S32 y, MASK mask)
// virtual
void LLButton::draw()
{
- F32 alpha = getDrawContext().mAlpha;
+ F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency();
bool flash = FALSE;
static LLUICachedControl<F32> button_flash_rate("ButtonFlashRate", 0);
static LLUICachedControl<S32> button_flash_count("ButtonFlashCount", 0);
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 2d5fefa78c..16aa49b653 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -124,6 +124,8 @@ public:
Optional<F32> hover_glow_amount;
Optional<TimeIntervalParam> held_down_delay;
+ Optional<bool> use_draw_context_alpha;
+
Params();
};
@@ -338,6 +340,8 @@ private:
S32 mImageOverlayTopPad;
S32 mImageOverlayBottomPad;
+ bool mUseDrawContextAlpha;
+
/*
* Space between image_overlay and label
*/
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index 2dabbc7767..70014fe4f5 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -769,7 +769,7 @@ BOOL LLComboBox::handleKeyHere(KEY key, MASK mask)
return FALSE;
}
// if selection has changed, pop open list
- else if (mList->getLastSelectedItem() != last_selected_item)
+ else if ((mList->getLastSelectedItem() != last_selected_item) || (key == KEY_DOWN) || (key == KEY_UP))
{
showList();
}
diff --git a/indra/llui/lldockcontrol.cpp b/indra/llui/lldockcontrol.cpp
index d48674f306..f6f5a0beb3 100644
--- a/indra/llui/lldockcontrol.cpp
+++ b/indra/llui/lldockcontrol.cpp
@@ -220,10 +220,15 @@ void LLDockControl::moveDockable()
case TOP:
x = dockRect.getCenterX() - dockableRect.getWidth() / 2;
y = dockRect.mTop + dockableRect.getHeight();
- // unique docking used with dock tongue, so add tongue height o the Y coordinate
+ // unique docking used with dock tongue, so add tongue height to the Y coordinate
if (use_tongue)
{
y += mDockTongue->getHeight();
+
+ if ( y > rootRect.mTop)
+ {
+ y = rootRect.mTop;
+ }
}
// check is dockable inside root view rect
@@ -257,7 +262,7 @@ void LLDockControl::moveDockable()
case BOTTOM:
x = dockRect.getCenterX() - dockableRect.getWidth() / 2;
y = dockRect.mBottom;
- // unique docking used with dock tongue, so add tongue height o the Y coordinate
+ // unique docking used with dock tongue, so add tongue height to the Y coordinate
if (use_tongue)
{
y -= mDockTongue->getHeight();
@@ -292,9 +297,21 @@ void LLDockControl::moveDockable()
break;
}
- // move dockable
- dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(),
- dockableRect.getHeight());
+ S32 max_available_height = rootRect.getHeight() - mDockTongueY - mDockTongue->getHeight();
+
+ // A floater should be shrunk so it doesn't cover a part of its docking tongue and
+ // there is a space between a dockable floater and a control to which it is docked.
+ if (use_tongue && dockableRect.getHeight() >= max_available_height)
+ {
+ dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(), max_available_height);
+ mDockableFloater->reshape(dockableRect.getWidth(), dockableRect.getHeight());
+ }
+ else
+ {
+ // move dockable
+ dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(),
+ dockableRect.getHeight());
+ }
LLRect localDocableParentRect;
mDockableFloater->getParent()->screenRectToLocal(dockableRect,
&localDocableParentRect);
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 34d8e9c500..7727e154da 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -61,10 +61,6 @@
// use this to control "jumping" behavior when Ctrl-Tabbing
const S32 TABBED_FLOATER_OFFSET = 0;
-// static
-F32 LLFloater::sActiveFloaterTransparency = 0.0f;
-F32 LLFloater::sInactiveFloaterTransparency = 0.0f;
-
std::string LLFloater::sButtonNames[BUTTON_COUNT] =
{
"llfloater_close_btn", //BUTTON_CLOSE
@@ -208,14 +204,14 @@ void LLFloater::initClass()
if (ctrl)
{
ctrl->getSignal()->connect(boost::bind(&LLFloater::updateActiveFloaterTransparency));
- sActiveFloaterTransparency = LLUI::sSettingGroups["config"]->getF32("ActiveFloaterTransparency");
+ updateActiveFloaterTransparency();
}
ctrl = LLUI::sSettingGroups["config"]->getControl("InactiveFloaterTransparency").get();
if (ctrl)
{
ctrl->getSignal()->connect(boost::bind(&LLFloater::updateInactiveFloaterTransparency));
- sInactiveFloaterTransparency = LLUI::sSettingGroups["config"]->getF32("InactiveFloaterTransparency");
+ updateInactiveFloaterTransparency();
}
}
@@ -225,7 +221,7 @@ static LLWidgetNameRegistry::StaticRegistrar sRegisterFloaterParams(&typeid(LLFl
LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
: LLPanel(), // intentionally do not pass params here, see initFromParams
- mDragHandle(NULL),
+ mDragHandle(NULL),
mTitle(p.title),
mShortTitle(p.short_title),
mSingleInstance(p.single_instance),
@@ -368,13 +364,13 @@ void LLFloater::layoutDragHandle()
// static
void LLFloater::updateActiveFloaterTransparency()
{
- sActiveFloaterTransparency = LLUI::sSettingGroups["config"]->getF32("ActiveFloaterTransparency");
+ sActiveControlTransparency = LLUI::sSettingGroups["config"]->getF32("ActiveFloaterTransparency");
}
// static
void LLFloater::updateInactiveFloaterTransparency()
{
- sInactiveFloaterTransparency = LLUI::sSettingGroups["config"]->getF32("InactiveFloaterTransparency");
+ sInactiveControlTransparency = LLUI::sSettingGroups["config"]->getF32("InactiveFloaterTransparency");
}
void LLFloater::addResizeCtrls()
@@ -1193,6 +1189,7 @@ void LLFloater::setFocus( BOOL b )
last_focus->setFocus(TRUE);
}
}
+ updateTransparency(this, b ? TT_ACTIVE : TT_INACTIVE);
}
// virtual
@@ -1652,7 +1649,7 @@ void LLFloater::onClickCloseBtn()
// virtual
void LLFloater::draw()
{
- mCurrentTransparency = hasFocus() ? sActiveFloaterTransparency : sInactiveFloaterTransparency;
+ const F32 alpha = getCurrentTransparency();
// draw background
if( isBackgroundVisible() )
@@ -1684,12 +1681,12 @@ void LLFloater::draw()
if (image)
{
// We're using images for this floater's backgrounds
- image->draw(getLocalRect(), overlay_color % mCurrentTransparency);
+ image->draw(getLocalRect(), overlay_color % alpha);
}
else
{
// We're not using images, use old-school flat colors
- gl_rect_2d( left, top, right, bottom, color % mCurrentTransparency );
+ gl_rect_2d( left, top, right, bottom, color % alpha );
// draw highlight on title bar to indicate focus. RDW
if(hasFocus()
@@ -1701,7 +1698,7 @@ void LLFloater::draw()
const LLFontGL* font = LLFontGL::getFontSansSerif();
LLRect r = getRect();
gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(), r.getHeight() - (S32)font->getLineHeight() - 1,
- titlebar_focus_color % mCurrentTransparency, 0, TRUE);
+ titlebar_focus_color % alpha, 0, TRUE);
}
}
}
@@ -1767,10 +1764,32 @@ void LLFloater::drawShadow(LLPanel* panel)
shadow_color.mV[VALPHA] *= 0.5f;
}
gl_drop_shadow(left, top, right, bottom,
- shadow_color % mCurrentTransparency,
+ shadow_color % getCurrentTransparency(),
llround(shadow_offset));
}
+void LLFloater::updateTransparency(LLView* view, ETypeTransparency transparency_type)
+{
+ child_list_t children = *view->getChildList();
+ child_list_t::iterator it = children.begin();
+
+ LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(view);
+ if (ctrl)
+ {
+ ctrl->setTransparencyType(transparency_type);
+ }
+
+ for(; it != children.end(); ++it)
+ {
+ updateTransparency(*it, transparency_type);
+ }
+}
+
+void LLFloater::updateTransparency(ETypeTransparency transparency_type)
+{
+ updateTransparency(this, transparency_type);
+}
+
void LLFloater::setCanMinimize(BOOL can_minimize)
{
// if removing minimize/restore button programmatically,
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index fa806bb632..bb96272d02 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -284,6 +284,8 @@ public:
static void setFloaterHost(LLMultiFloater* hostp) {sHostp = hostp; }
static LLMultiFloater* getFloaterHost() {return sHostp; }
+
+ void updateTransparency(ETypeTransparency transparency_type);
protected:
@@ -343,6 +345,7 @@ private:
static void updateActiveFloaterTransparency();
static void updateInactiveFloaterTransparency();
+ void updateTransparency(LLView* view, ETypeTransparency transparency_type);
public:
// Called when floater is opened, passes mKey
@@ -411,11 +414,6 @@ private:
bool mDocked;
bool mTornOff;
- F32 mCurrentTransparency;
-
- static F32 sActiveFloaterTransparency;
- static F32 sInactiveFloaterTransparency;
-
static LLMultiFloater* sHostp;
static BOOL sQuitting;
static std::string sButtonNames[BUTTON_COUNT];
diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp
index 627957061d..47f2cfaf89 100644
--- a/indra/llui/lliconctrl.cpp
+++ b/indra/llui/lliconctrl.cpp
@@ -41,6 +41,7 @@ static LLDefaultChildRegistry::Register<LLIconCtrl> r("icon");
LLIconCtrl::Params::Params()
: image("image_name"),
color("color"),
+ use_draw_context_alpha("use_draw_context_alpha", true),
scale_image("scale_image")
{
tab_stop = false;
@@ -51,6 +52,7 @@ LLIconCtrl::LLIconCtrl(const LLIconCtrl::Params& p)
: LLUICtrl(p),
mColor(p.color()),
mImagep(p.image),
+ mUseDrawContextAlpha(p.use_draw_context_alpha),
mPriority(0),
mDrawWidth(0),
mDrawHeight(0)
@@ -71,7 +73,8 @@ void LLIconCtrl::draw()
{
if( mImagep.notNull() )
{
- mImagep->draw(getLocalRect(), mColor.get() % getDrawContext().mAlpha );
+ const F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency();
+ mImagep->draw(getLocalRect(), mColor.get() % alpha );
}
LLUICtrl::draw();
diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h
index 79a8b0fb28..e9bdab2d47 100644
--- a/indra/llui/lliconctrl.h
+++ b/indra/llui/lliconctrl.h
@@ -48,6 +48,7 @@ public:
{
Optional<LLUIImage*> image;
Optional<LLUIColor> color;
+ Optional<bool> use_draw_context_alpha;
Ignored scale_image;
Params();
};
@@ -79,6 +80,10 @@ protected:
S32 mDrawWidth ;
S32 mDrawHeight ;
+ // If set to true (default), use the draw context transparency.
+ // If false, will use transparency returned by getCurrentTransparency(). See STORM-698.
+ bool mUseDrawContextAlpha;
+
private:
LLUIColor mColor;
LLPointer<LLUIImage> mImagep;
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 3eb58e1aec..ba73b74052 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -1530,7 +1530,8 @@ void LLLineEditor::drawBackground()
image = mBgImage;
}
- F32 alpha = getDrawContext().mAlpha;
+ F32 alpha = getCurrentTransparency();
+
// optionally draw programmatic border
if (has_focus)
{
diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp
index ac568a83e4..eed0085273 100644
--- a/indra/llui/llmenubutton.cpp
+++ b/indra/llui/llmenubutton.cpp
@@ -175,6 +175,13 @@ void LLMenuButton::updateMenuOrigin()
mY = rect.mTop + mMenuHandle.get()->getRect().getHeight();
break;
}
+ case MP_TOP_RIGHT:
+ {
+ const LLRect& menu_rect = mMenuHandle.get()->getRect();
+ mX = rect.mRight - menu_rect.getWidth();
+ mY = rect.mTop + menu_rect.getHeight();
+ break;
+ }
case MP_BOTTOM_LEFT:
{
mX = rect.mLeft;
diff --git a/indra/llui/llmenubutton.h b/indra/llui/llmenubutton.h
index 9e91b9e99d..7b657595da 100644
--- a/indra/llui/llmenubutton.h
+++ b/indra/llui/llmenubutton.h
@@ -47,6 +47,7 @@ public:
typedef enum e_menu_position
{
MP_TOP_LEFT,
+ MP_TOP_RIGHT,
MP_BOTTOM_LEFT
} EMenuPosition;
diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp
index 900e2c789e..ff377ba3a1 100644
--- a/indra/llui/llpanel.cpp
+++ b/indra/llui/llpanel.cpp
@@ -194,6 +194,8 @@ void LLPanel::draw()
// draw background
if( mBgVisible )
{
+ alpha = getCurrentTransparency();
+
LLRect local_rect = getLocalRect();
if (mBgOpaque )
{
diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp
index 3146418a7d..380c477eb2 100644
--- a/indra/llui/llscrollcontainer.cpp
+++ b/indra/llui/llscrollcontainer.cpp
@@ -422,9 +422,10 @@ void LLScrollContainer::draw()
// Draw background
if( mIsOpaque )
{
+ F32 alpha = getCurrentTransparency();
+
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.color4fv( mBackgroundColor.get().mV );
- gl_rect_2d( mInnerRect );
+ gl_rect_2d(mInnerRect, mBackgroundColor.get() % alpha);
}
// Draw mScrolledViews and update scroll bars.
diff --git a/indra/llui/llscrolllistcolumn.cpp b/indra/llui/llscrolllistcolumn.cpp
index 2a4c1ca44c..696e4a2bb1 100644
--- a/indra/llui/llscrolllistcolumn.cpp
+++ b/indra/llui/llscrolllistcolumn.cpp
@@ -83,7 +83,14 @@ void LLScrollColumnHeader::draw()
&& (sort_column == mColumn->mSortingColumn || sort_column == mColumn->mName);
BOOL is_ascending = mColumn->mParentCtrl->getSortAscending();
- setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, draw_arrow ? LLColor4::white : LLColor4::transparent);
+ if (draw_arrow)
+ {
+ setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, LLColor4::white);
+ }
+ else
+ {
+ setImageOverlay(LLUUID::null);
+ }
// Draw children
LLButton::draw();
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 7df7c13dc0..8854f0a02e 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -1482,8 +1482,9 @@ void LLScrollListCtrl::draw()
// Draw background
if (mBackgroundVisible)
{
+ F32 alpha = getCurrentTransparency();
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gl_rect_2d(background, getEnabled() ? mBgWriteableColor.get() : mBgReadOnlyColor.get() );
+ gl_rect_2d(background, getEnabled() ? mBgWriteableColor.get() % alpha : mBgReadOnlyColor.get() % alpha );
}
if (mColumnsDirty)
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 3f213ed13e..49537ef78f 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -1005,6 +1005,7 @@ void LLTextBase::draw()
if (mBGVisible)
{
+ F32 alpha = getCurrentTransparency();
// clip background rect against extents, if we support scrolling
LLRect bg_rect = mVisibleTextRect;
if (mScroller)
@@ -1016,7 +1017,7 @@ void LLTextBase::draw()
: hasFocus()
? mFocusBgColor.get()
: mWriteableBgColor.get();
- gl_rect_2d(doc_rect, bg_color, TRUE);
+ gl_rect_2d(doc_rect, bg_color % alpha, TRUE);
}
// draw document view
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index ff9af21e54..1e2fe09cd9 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -950,7 +950,7 @@ void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor
}
// Draw gray and white checkerboard with black border
-void gl_rect_2d_checkerboard(const LLRect& rect)
+void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha)
{
// Initialize the first time this is called.
const S32 PIXELS = 32;
@@ -971,11 +971,11 @@ void gl_rect_2d_checkerboard(const LLRect& rect)
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
// ...white squares
- gGL.color3f( 1.f, 1.f, 1.f );
+ gGL.color4f( 1.f, 1.f, 1.f, alpha );
gl_rect_2d(rect);
// ...gray squares
- gGL.color3f( .7f, .7f, .7f );
+ gGL.color4f( .7f, .7f, .7f, alpha );
gGL.flush();
glPolygonStipple( checkerboard );
@@ -1620,7 +1620,10 @@ void LLUI::initClass(const settings_map_t& settings,
void LLUI::cleanupClass()
{
- sImageProvider->cleanUp();
+ if(sImageProvider)
+ {
+ sImageProvider->cleanUp();
+ }
}
void LLUI::setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t& remove_popup, const clear_popups_t& clear_popups)
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index fc545c85d5..62d10df8b2 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -79,7 +79,7 @@ void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, const LL
void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, S32 pixel_offset = 0, BOOL filled = TRUE );
void gl_rect_2d(const LLRect& rect, BOOL filled = TRUE );
void gl_rect_2d(const LLRect& rect, const LLColor4& color, BOOL filled = TRUE );
-void gl_rect_2d_checkerboard(const LLRect& rect);
+void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha = 1.0f);
void gl_drop_shadow(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &start_color, S32 lines);
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 3ac3bf8c41..7e4cb78d80 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -36,6 +36,9 @@
static LLDefaultChildRegistry::Register<LLUICtrl> r("ui_ctrl");
+F32 LLUICtrl::sActiveControlTransparency = 1.0f;
+F32 LLUICtrl::sInactiveControlTransparency = 1.0f;
+
// Compiler optimization, generate extern template
template class LLUICtrl* LLView::getChild<class LLUICtrl>(
const std::string& name, BOOL recurse) const;
@@ -110,7 +113,8 @@ LLUICtrl::LLUICtrl(const LLUICtrl::Params& p, const LLViewModelPtr& viewmodel)
mMouseUpSignal(NULL),
mRightMouseDownSignal(NULL),
mRightMouseUpSignal(NULL),
- mDoubleClickSignal(NULL)
+ mDoubleClickSignal(NULL),
+ mTransparencyType(TT_DEFAULT)
{
mUICtrlHandle.bind(this);
}
@@ -923,6 +927,33 @@ BOOL LLUICtrl::getTentative() const
void LLUICtrl::setColor(const LLColor4& color)
{ }
+F32 LLUICtrl::getCurrentTransparency()
+{
+ F32 alpha = 0;
+
+ switch(mTransparencyType)
+ {
+ case TT_DEFAULT:
+ alpha = getDrawContext().mAlpha;
+ break;
+
+ case TT_ACTIVE:
+ alpha = sActiveControlTransparency;
+ break;
+
+ case TT_INACTIVE:
+ alpha = sInactiveControlTransparency;
+ break;
+ }
+
+ return alpha;
+}
+
+void LLUICtrl::setTransparencyType(ETypeTransparency type)
+{
+ mTransparencyType = type;
+}
+
boost::signals2::connection LLUICtrl::setCommitCallback( const commit_signal_t::slot_type& cb )
{
if (!mCommitSignal) mCommitSignal = new commit_signal_t();
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index 76dfdf754c..a78f98ac76 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -120,6 +120,12 @@ public:
Params();
};
+ enum ETypeTransparency
+ {
+ TT_DEFAULT,
+ TT_ACTIVE,
+ TT_INACTIVE
+ };
/*virtual*/ ~LLUICtrl();
void initFromParams(const Params& p);
@@ -202,6 +208,11 @@ public:
virtual void setColor(const LLColor4& color);
+ F32 getCurrentTransparency();
+
+ void setTransparencyType(ETypeTransparency type);
+ ETypeTransparency getTransparencyType() const {return mTransparencyType;}
+
BOOL focusNextItem(BOOL text_entry_only);
BOOL focusPrevItem(BOOL text_entry_only);
BOOL focusFirstItem(BOOL prefer_text_fields = FALSE, BOOL focus_flash = TRUE );
@@ -283,6 +294,10 @@ protected:
boost::signals2::connection mMakeVisibleControlConnection;
LLControlVariable* mMakeInvisibleControlVariable;
boost::signals2::connection mMakeInvisibleControlConnection;
+
+ static F32 sActiveControlTransparency;
+ static F32 sInactiveControlTransparency;
+
private:
BOOL mTabStop;
@@ -290,6 +305,8 @@ private:
BOOL mTentative;
LLRootHandle<LLUICtrl> mUICtrlHandle;
+ ETypeTransparency mTransparencyType;
+
class DefaultTabGroupFirstSorter;
};
diff --git a/indra/llvfs/tests/lldir_test.cpp b/indra/llvfs/tests/lldir_test.cpp
index 83ccb277b3..8788bd63e8 100644
--- a/indra/llvfs/tests/lldir_test.cpp
+++ b/indra/llvfs/tests/lldir_test.cpp
@@ -263,7 +263,9 @@ namespace tut
std::string path = dir + delim + file;
LLFILE* handle = LLFile::fopen( path, "w" );
ensure("failed to open test file '"+path+"'", handle != NULL );
- ensure("failed to write to test file '"+path+"'", !fputs("test file", handle) );
+ // 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);
fclose(handle);
return path;
}
diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp
index f9a39826f5..27c694dde9 100644
--- a/indra/llxml/llcontrol.cpp
+++ b/indra/llxml/llcontrol.cpp
@@ -1107,7 +1107,7 @@ bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, const std::strin
return sd.asBoolean();
else
{
- CONTROL_ERRS << "Invalid BOOL value" << llendl;
+ CONTROL_ERRS << "Invalid BOOL value for " << control_name << ": " << sd << llendl;
return FALSE;
}
}
@@ -1119,7 +1119,7 @@ S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, const std::string&
return sd.asInteger();
else
{
- CONTROL_ERRS << "Invalid S32 value" << llendl;
+ CONTROL_ERRS << "Invalid S32 value for " << control_name << ": " << sd << llendl;
return 0;
}
}
@@ -1131,7 +1131,7 @@ U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, const std::string&
return sd.asInteger();
else
{
- CONTROL_ERRS << "Invalid U32 value" << llendl;
+ CONTROL_ERRS << "Invalid U32 value for " << control_name << ": " << sd << llendl;
return 0;
}
}
@@ -1143,7 +1143,7 @@ F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, const std::string&
return (F32) sd.asReal();
else
{
- CONTROL_ERRS << "Invalid F32 value" << llendl;
+ CONTROL_ERRS << "Invalid F32 value for " << control_name << ": " << sd << llendl;
return 0.0f;
}
}
@@ -1155,7 +1155,7 @@ std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, co
return sd.asString();
else
{
- CONTROL_ERRS << "Invalid string value" << llendl;
+ CONTROL_ERRS << "Invalid string value for " << control_name << ": " << sd << llendl;
return LLStringUtil::null;
}
}
@@ -1173,7 +1173,7 @@ LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, const
return (LLVector3)sd;
else
{
- CONTROL_ERRS << "Invalid LLVector3 value" << llendl;
+ CONTROL_ERRS << "Invalid LLVector3 value for " << control_name << ": " << sd << llendl;
return LLVector3::zero;
}
}
@@ -1185,7 +1185,7 @@ LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, cons
return (LLVector3d)sd;
else
{
- CONTROL_ERRS << "Invalid LLVector3d value" << llendl;
+ CONTROL_ERRS << "Invalid LLVector3d value for " << control_name << ": " << sd << llendl;
return LLVector3d::zero;
}
}
@@ -1197,7 +1197,7 @@ LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, const std::s
return LLRect(sd);
else
{
- CONTROL_ERRS << "Invalid rect value" << llendl;
+ CONTROL_ERRS << "Invalid rect value for " << control_name << ": " << sd << llendl;
return LLRect::null;
}
}
@@ -1211,19 +1211,19 @@ LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, const st
LLColor4 color(sd);
if (color.mV[VRED] < 0.f || color.mV[VRED] > 1.f)
{
- llwarns << "Color " << control_name << " value out of range " << llendl;
+ llwarns << "Color " << control_name << " red value out of range: " << color << llendl;
}
else if (color.mV[VGREEN] < 0.f || color.mV[VGREEN] > 1.f)
{
- llwarns << "Color " << control_name << " value out of range " << llendl;
+ llwarns << "Color " << control_name << " green value out of range: " << color << llendl;
}
else if (color.mV[VBLUE] < 0.f || color.mV[VBLUE] > 1.f)
{
- llwarns << "Color " << control_name << " value out of range " << llendl;
+ llwarns << "Color " << control_name << " blue value out of range: " << color << llendl;
}
else if (color.mV[VALPHA] < 0.f || color.mV[VALPHA] > 1.f)
{
- llwarns << "Color " << control_name << " value out of range " << llendl;
+ llwarns << "Color " << control_name << " alpha value out of range: " << color << llendl;
}
return LLColor4(sd);
@@ -1242,7 +1242,7 @@ LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, const st
return sd;
else
{
- CONTROL_ERRS << "Invalid LLColor3 value" << llendl;
+ CONTROL_ERRS << "Invalid LLColor3 value for " << control_name << ": " << sd << llendl;
return LLColor3::white;
}
}
diff --git a/indra/mac_updater/mac_updater.cpp b/indra/mac_updater/mac_updater.cpp
index 23980ffac2..5d19e8a889 100644
--- a/indra/mac_updater/mac_updater.cpp
+++ b/indra/mac_updater/mac_updater.cpp
@@ -26,6 +26,9 @@
#include "linden_common.h"
+#include <boost/format.hpp>
+
+#include <libgen.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -62,6 +65,8 @@ Boolean gCancelled = false;
const char *gUpdateURL;
const char *gProductName;
const char *gBundleID;
+const char *gDmgFile;
+const char *gMarkerPath;
void *updatethreadproc(void*);
@@ -334,6 +339,14 @@ int parse_args(int argc, char **argv)
{
gBundleID = argv[j];
}
+ else if ((!strcmp(argv[j], "-dmg")) && (++j < argc))
+ {
+ gDmgFile = argv[j];
+ }
+ else if ((!strcmp(argv[j], "-marker")) && (++j < argc))
+ {
+ gMarkerPath = argv[j];;
+ }
}
return 0;
@@ -361,10 +374,12 @@ int main(int argc, char **argv)
gUpdateURL = NULL;
gProductName = NULL;
gBundleID = NULL;
+ gDmgFile = NULL;
+ gMarkerPath = NULL;
parse_args(argc, argv);
- if (!gUpdateURL)
+ if ((gUpdateURL == NULL) && (gDmgFile == NULL))
{
- llinfos << "Usage: mac_updater -url <url> [-name <product_name>] [-program <program_name>]" << llendl;
+ llinfos << "Usage: mac_updater -url <url> | -dmg <dmg file> [-name <product_name>] [-program <program_name>]" << llendl;
exit(1);
}
else
@@ -488,11 +503,18 @@ int main(int argc, char **argv)
NULL,
&retval_mac);
}
-
+
+ if(gMarkerPath != 0)
+ {
+ // Create a install fail marker that can be used by the viewer to
+ // detect install problems.
+ std::ofstream stream(gMarkerPath);
+ if(stream) stream << -1;
+ }
+ exit(-1);
+ } else {
+ exit(0);
}
-
- // Don't dispose of things, just exit. This keeps the update thread from potentially getting hosed.
- exit(0);
if(gWindow != NULL)
{
@@ -700,17 +722,26 @@ static OSErr findAppBundleOnDiskImage(FSRef *parent, FSRef *app)
// Looks promising. Check to see if it has the right bundle identifier.
if(isFSRefViewerBundle(&ref))
{
+ llinfos << name << " is the one" << llendl;
// This is the one. Return it.
*app = ref;
found = true;
+ break;
+ } else {
+ llinfos << name << " is not the bundle we are looking for; move along" << llendl;
}
+
}
}
}
}
- while(!err && !found);
+ while(!err);
+
+ llinfos << "closing the iterator" << llendl;
FSCloseIterator(iterator);
+
+ llinfos << "closed" << llendl;
}
if(!err && !found)
@@ -921,6 +952,22 @@ void *updatethreadproc(void*)
#endif // 0 *HACK for DEV-11935
+ // Skip downloading the file if the dmg was passed on the command line.
+ std::string dmgName;
+ if(gDmgFile != NULL) {
+ dmgName = basename((char *)gDmgFile);
+ char * dmgDir = dirname((char *)gDmgFile);
+ strncpy(tempDir, dmgDir, sizeof(tempDir));
+ err = FSPathMakeRef((UInt8*)tempDir, &tempDirRef, NULL);
+ if(err != noErr) throw 0;
+ chdir(tempDir);
+ goto begin_install;
+ } else {
+ // Continue on to download file.
+ dmgName = "SecondLife.dmg";
+ }
+
+
strncat(temp, "/SecondLifeUpdate_XXXXXX", (sizeof(temp) - strlen(temp)) - 1);
if(mkdtemp(temp) == NULL)
{
@@ -979,14 +1026,17 @@ void *updatethreadproc(void*)
fclose(downloadFile);
downloadFile = NULL;
}
-
+
+ begin_install:
sendProgress(0, 0, CFSTR("Mounting image..."));
LLFile::mkdir("mnt", 0700);
// NOTE: we could add -private at the end of this command line to keep the image from showing up in the Finder,
// but if our cleanup fails, this makes it much harder for the user to unmount the image.
std::string mountOutput;
- FILE* mounter = popen("hdiutil attach SecondLife.dmg -mountpoint mnt", "r"); /* Flawfinder: ignore */
+ boost::format cmdFormat("hdiutil attach %s -mountpoint mnt");
+ cmdFormat % dmgName;
+ FILE* mounter = popen(cmdFormat.str().c_str(), "r"); /* Flawfinder: ignore */
if(mounter == NULL)
{
@@ -1052,12 +1102,19 @@ void *updatethreadproc(void*)
throw 0;
}
+ sendProgress(0, 0, CFSTR("Searching for the app bundle..."));
err = findAppBundleOnDiskImage(&mountRef, &sourceRef);
if(err != noErr)
{
llinfos << "Couldn't find application bundle on mounted disk image." << llendl;
throw 0;
}
+ else
+ {
+ llinfos << "found the bundle." << llendl;
+ }
+
+ sendProgress(0, 0, CFSTR("Preparing to copy files..."));
FSRef asideRef;
char aside[MAX_PATH]; /* Flawfinder: ignore */
@@ -1077,7 +1134,11 @@ void *updatethreadproc(void*)
// Move aside old version (into work directory)
err = FSMoveObject(&targetRef, &tempDirRef, &asideRef);
if(err != noErr)
+ {
+ llwarns << "failed to move aside old version (error code " <<
+ err << ")" << llendl;
throw 0;
+ }
// Grab the path for later use.
err = FSRefMakePath(&asideRef, (UInt8*)aside, sizeof(aside));
@@ -1175,6 +1236,10 @@ void *updatethreadproc(void*)
llinfos << "Moving work directory to the trash." << llendl;
err = FSMoveObject(&tempDirRef, &trashFolderRef, NULL);
+ if(err != noErr) {
+ llwarns << "failed to move files to trash, (error code " <<
+ err << ")" << llendl;
+ }
// snprintf(temp, sizeof(temp), "rm -rf '%s'", tempDir);
// printf("%s\n", temp);
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 7724f41931..f5bcf69295 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -64,6 +64,7 @@ include_directories(
${LSCRIPT_INCLUDE_DIRS}
${LSCRIPT_INCLUDE_DIRS}/lscript_compile
${LLLOGIN_INCLUDE_DIRS}
+ ${UPDATER_INCLUDE_DIRS}
)
set(viewer_SOURCE_FILES
@@ -284,6 +285,7 @@ set(viewer_SOURCE_FILES
llloginhandler.cpp
lllogininstance.cpp
llmachineid.cpp
+ llmainlooprepeater.cpp
llmanip.cpp
llmaniprotate.cpp
llmanipscale.cpp
@@ -445,6 +447,7 @@ set(viewer_SOURCE_FILES
lltoastimpanel.cpp
lltoastnotifypanel.cpp
lltoastpanel.cpp
+ lltoastscripttextbox.cpp
lltool.cpp
lltoolbrush.cpp
lltoolcomp.cpp
@@ -818,6 +821,7 @@ set(viewer_HEADER_FILES
llloginhandler.h
lllogininstance.h
llmachineid.h
+ llmainlooprepeater.h
llmanip.h
llmaniprotate.h
llmanipscale.h
@@ -976,6 +980,7 @@ set(viewer_HEADER_FILES
lltoastimpanel.h
lltoastnotifypanel.h
lltoastpanel.h
+ lltoastscripttextbox.h
lltool.h
lltoolbrush.h
lltoolcomp.h
@@ -1646,7 +1651,14 @@ if (WINDOWS)
endif (PACKAGE)
endif (WINDOWS)
+# *NOTE - this list is very sensitive to ordering, test carefully on all
+# platforms if you change the releative order of the entries here.
+# In particular, cmake 2.6.4 (when buidling with linux/makefile generators)
+# appears to sometimes de-duplicate redundantly listed dependencies improperly.
+# To work around this, higher level modules should be listed before the modules
+# that they depend upon. -brad
target_link_libraries(${VIEWER_BINARY_NAME}
+ ${UPDATER_LIBRARIES}
${LLAUDIO_LIBRARIES}
${LLCHARACTER_LIBRARIES}
${LLIMAGE_LIBRARIES}
@@ -1833,10 +1845,18 @@ if (PACKAGE)
set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest)
endif (LINUX)
+ if(CMAKE_CFG_INTDIR STREQUAL ".")
+ set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE})
+ else(CMAKE_CFG_INTDIR STREQUAL ".")
+ # set LLBUILD_CONFIG to be a shell variable evaluated at build time
+ # reflecting the configuration we are currently building.
+ set(LLBUILD_CONFIG ${CMAKE_CFG_INTDIR})
+ endif(CMAKE_CFG_INTDIR STREQUAL ".")
add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}"
COMMAND "${PYTHON_EXECUTABLE}"
ARGS
"${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py"
+ "${LLBUILD_CONFIG}"
"${VIEWER_DIST_DIR}"
"${VIEWER_EXE_GLOBS}"
"${VIEWER_LIB_GLOB}"
@@ -1845,7 +1865,7 @@ if (PACKAGE)
DEPENDS generate_breakpad_symbols.py
VERBATIM
)
- add_custom_target(generate_breakpad_symbols ALL DEPENDS "${VIEWER_SYMBOL_FILE}")
+ add_custom_target(generate_breakpad_symbols DEPENDS "${VIEWER_SYMBOL_FILE}")
add_dependencies(generate_breakpad_symbols "${VIEWER_BINARY_NAME}" "${VIEWER_COPY_MANIFEST}")
add_dependencies(package generate_breakpad_symbols)
endif (PACKAGE)
@@ -1859,7 +1879,9 @@ if (LL_TESTS)
lldateutil.cpp
llmediadataclient.cpp
lllogininstance.cpp
+ llremoteparcelrequest.cpp
llviewerhelputil.cpp
+ llversioninfo.cpp
)
##################################################
diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml
index 0562cf5480..1b8393330d 100644
--- a/indra/newview/app_settings/cmd_line.xml
+++ b/indra/newview/app_settings/cmd_line.xml
@@ -363,8 +363,7 @@
<map>
<key>count</key>
<integer>1</integer>
- <key>map-to</key>
- <string>VersionChannelName</string>
+ <!-- Special case. Not mapped to a setting. -->
</map>
<key>loginpage</key>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index aad2fe3276..402a0e85c4 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1365,6 +1365,17 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>LetterKeysFocusChatBar</key>
+ <map>
+ <key>Comment</key>
+ <string>When printable characters keys (possibly with Shift held) are pressed, the chatbar takes focus</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>ChatBubbleOpacity</key>
<map>
<key>Comment</key>
@@ -4006,7 +4017,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
- <real>0.5</real>
+ <real>0.65</real>
</map>
<key>InBandwidth</key>
<map>
@@ -11079,7 +11090,62 @@
<key>Value</key>
<integer>15</integer>
</map>
- <key>UploadBakedTexOld</key>
+ <key>UpdaterServiceActive</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable or disable the updater service.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>UpdaterServiceCheckPeriod</key>
+ <map>
+ <key>Comment</key>
+ <string>Default period between update checking.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>3600</integer>
+ </map>
+ <key>UpdaterServiceURL</key>
+ <map>
+ <key>Comment</key>
+ <string>Default location for the updater service.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>https://update.secondlife.com</string>
+ </map>
+ <key>UpdaterServicePath</key>
+ <map>
+ <key>Comment</key>
+ <string>Path on the update server host.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>update</string>
+ </map>
+ <key>UpdaterServiceProtocolVersion</key>
+ <map>
+ <key>Comment</key>
+ <string>The update protocol version to use.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>v1.0</string>
+ </map>
+ <key>UploadBakedTexOld</key>
<map>
<key>Comment</key>
<string>Forces the baked texture pipeline to upload using the old method.</string>
@@ -11432,17 +11498,6 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>VersionChannelName</key>
- <map>
- <key>Comment</key>
- <string>Versioning Channel Name.</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>Second Life Release</string>
- </map>
<key>VertexShaderEnable</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/generate_breakpad_symbols.py b/indra/newview/generate_breakpad_symbols.py
index 8f2dfd2348..4fd04d780e 100644
--- a/indra/newview/generate_breakpad_symbols.py
+++ b/indra/newview/generate_breakpad_symbols.py
@@ -31,6 +31,7 @@ import fnmatch
import itertools
import operator
import os
+import re
import sys
import shlex
import subprocess
@@ -45,8 +46,12 @@ class MissingModuleError(Exception):
Exception.__init__(self, "Failed to find required modules: %r" % modules)
self.modules = modules
-def main(viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file):
- print "generate_breakpad_symbols run with args: %s" % str((viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file))
+def main(configuration, viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file):
+ print "generate_breakpad_symbols run with args: %s" % str((configuration, viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file))
+
+ if not re.match("release", configuration, re.IGNORECASE):
+ print "skipping breakpad symbol generation for non-release build."
+ return 0
# split up list of viewer_exes
# "'Second Life' SLPlugin" becomes ['Second Life', 'SLPlugin']
@@ -122,7 +127,7 @@ def main(viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_fil
return 0
if __name__ == "__main__":
- if len(sys.argv) != 6:
+ if len(sys.argv) != 7:
usage()
sys.exit(1)
sys.exit(main(*sys.argv[1:]))
diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index d5712f80cf..4e8ed807ee 100644
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -85,6 +85,8 @@ AutoCloseWindow true ; after all files install, close window
InstallDir "$PROGRAMFILES\${INSTNAME}"
InstallDirRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" ""
DirText $(DirectoryChooseTitle) $(DirectoryChooseSetup)
+Page directory dirPre
+Page instfiles
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Variables
@@ -95,6 +97,8 @@ Var INSTFLAGS
Var INSTSHORTCUT
Var COMMANDLINE ; command line passed to this installer, set in .onInit
Var SHORTCUT_LANG_PARAM ; "--set InstallLanguage de", passes language to viewer
+Var SKIP_DIALOGS ; set from command line in .onInit. autoinstall
+ ; GUI and the defaults.
;;; Function definitions should go before file includes, because calls to
;;; DLLs like LangDLL trigger an implicit file include, so if that call is at
@@ -110,6 +114,9 @@ Var SHORTCUT_LANG_PARAM ; "--set InstallLanguage de", passes language to viewer
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Function .onInstSuccess
Push $R0 # Option value, unused
+
+ StrCmp $SKIP_DIALOGS "true" label_launch
+
${GetOptions} $COMMANDLINE "/AUTOSTART" $R0
# If parameter was there (no error) just launch
# Otherwise ask
@@ -128,6 +135,13 @@ label_no_launch:
Pop $R0
FunctionEnd
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Pre-directory page callback
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function dirPre
+ StrCmp $SKIP_DIALOGS "true" 0 +2
+ Abort
+FunctionEnd
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Make sure we're not on Windows 98 / ME
@@ -145,7 +159,8 @@ Function CheckWindowsVersion
StrCmp $R0 "NT" win_ver_bad
Return
win_ver_bad:
- MessageBox MB_YESNO $(CheckWindowsVersionMB) IDNO win_ver_abort
+ StrCmp $SKIP_DIALOGS "true" +2 ; If skip_dialogs is set just install
+ MessageBox MB_YESNO $(CheckWindowsVersionMB) IDNO win_ver_abort
Return
win_ver_abort:
Quit
@@ -184,13 +199,13 @@ FunctionEnd
; If it has, allow user to bail out of install process.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Function CheckIfAlreadyCurrent
- Push $0
- ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Version"
- StrCmp $0 ${VERSION_LONG} 0 DONE
- MessageBox MB_OKCANCEL $(CheckIfCurrentMB) /SD IDOK IDOK DONE
+ Push $0
+ ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Version"
+ StrCmp $0 ${VERSION_LONG} 0 continue_install
+ StrCmp $SKIP_DIALOGS "true" continue_install
+ MessageBox MB_OKCANCEL $(CheckIfCurrentMB) /SD IDOK IDOK continue_install
Quit
-
- DONE:
+continue_install:
Pop $0
Return
FunctionEnd
@@ -203,7 +218,9 @@ Function CloseSecondLife
Push $0
FindWindow $0 "Second Life" ""
IntCmp $0 0 DONE
- MessageBox MB_OKCANCEL $(CloseSecondLifeInstMB) IDOK CLOSE IDCANCEL CANCEL_INSTALL
+
+ StrCmp $SKIP_DIALOGS "true" CLOSE
+ MessageBox MB_OKCANCEL $(CloseSecondLifeInstMB) IDOK CLOSE IDCANCEL CANCEL_INSTALL
CANCEL_INSTALL:
Quit
@@ -659,23 +676,29 @@ FunctionEnd
Function .onInit
Push $0
${GetParameters} $COMMANDLINE ; get our command line
+
+ ${GetOptions} $COMMANDLINE "/SKIP_DIALOGS" $0
+ IfErrors +2 0 ; If error jump past setting SKIP_DIALOGS
+ StrCpy $SKIP_DIALOGS "true"
+
${GetOptions} $COMMANDLINE "/LANGID=" $0 ; /LANGID=1033 implies US English
; If no language (error), then proceed
- IfErrors lbl_check_silent
+ IfErrors lbl_configure_default_lang
; No error means we got a language, so use it
StrCpy $LANGUAGE $0
Goto lbl_return
-lbl_check_silent:
- ; For silent installs, no language prompt, use default
- IfSilent lbl_return
-
- ; If we currently have a version of SL installed, default to the language of that install
+lbl_configure_default_lang:
+ ; If we currently have a version of SL installed, default to the language of that install
; Otherwise don't change $LANGUAGE and it will default to the OS UI language.
- ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage"
- IfErrors lbl_build_menu
+ ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage"
+ IfErrors +2 0 ; If error skip the copy instruction
StrCpy $LANGUAGE $0
+ ; For silent installs, no language prompt, use default
+ IfSilent lbl_return
+ StrCmp $SKIP_DIALOGS "true" lbl_return
+
lbl_build_menu:
Push ""
# Use separate file so labels can be UTF-16 but we can still merge changes
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index c9bd7851ed..001a6a8851 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -56,9 +56,9 @@
#include "llparcel.h"
#include "llrendersphere.h"
#include "llsdutil.h"
-#include "llsidetray.h"
#include "llsky.h"
#include "llsmoothstep.h"
+#include "llstartup.h"
#include "llstatusbar.h"
#include "llteleportflags.h"
#include "lltool.h"
@@ -1726,9 +1726,6 @@ void LLAgent::endAnimationUpdateUI()
LLBottomTray::getInstance()->onMouselookModeOut();
- LLSideTray::getInstance()->getButtonsPanel()->setVisible(TRUE);
- LLSideTray::getInstance()->updateSidetrayVisibility();
-
LLPanelStandStopFlying::getInstance()->setVisible(TRUE);
LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
@@ -1828,9 +1825,6 @@ void LLAgent::endAnimationUpdateUI()
LLBottomTray::getInstance()->onMouselookModeIn();
- LLSideTray::getInstance()->getButtonsPanel()->setVisible(FALSE);
- LLSideTray::getInstance()->updateSidetrayVisibility();
-
LLPanelStandStopFlying::getInstance()->setVisible(FALSE);
// clear out camera lag effect
@@ -2452,7 +2446,7 @@ BOOL LLAgent::setUserGroupFlags(const LLUUID& group_id, BOOL accept_notices, BOO
BOOL LLAgent::canJoinGroups() const
{
- return mGroups.count() < MAX_AGENT_GROUPS;
+ return mGroups.count() < gMaxAgentGroups;
}
LLQuaternion LLAgent::getHeadRotation()
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index 6c598d5d71..aebebad96a 100644
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -33,6 +33,7 @@
#include "llagentconstants.h"
#include "llagentdata.h" // gAgentID, gAgentSessionID
#include "llcharacter.h" // LLAnimPauseRequest
+#include "llcoordframe.h" // for mFrameAgent
#include "llpointer.h"
#include "lluicolor.h"
#include "llvoavatardefines.h"
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index f66663891d..6c07974f69 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -83,6 +83,7 @@
#include "llweb.h"
#include "llsecondlifeurls.h"
+#include "llupdaterservice.h"
// Linden library includes
#include "llavatarnamecache.h"
@@ -196,6 +197,8 @@
#include "llsecapi.h"
#include "llmachineid.h"
+#include "llmainlooprepeater.h"
+
// *FIX: These extern globals should be cleaned up.
// The globals either represent state/config/resource-storage of either
// this app, or another 'component' of the viewer. App globals should be
@@ -576,7 +579,8 @@ LLAppViewer::LLAppViewer() :
mAgentRegionLastAlive(false),
mRandomizeFramerate(LLCachedControl<bool>(gSavedSettings,"Randomize Framerate", FALSE)),
mPeriodicSlowFrame(LLCachedControl<bool>(gSavedSettings,"Periodic Slow Frame", FALSE)),
- mFastTimerLogThread(NULL)
+ mFastTimerLogThread(NULL),
+ mUpdater(new LLUpdaterService())
{
if(NULL != sInstance)
{
@@ -652,10 +656,13 @@ bool LLAppViewer::init()
initThreads();
writeSystemInfo();
- // Build a string representing the current version number.
- gCurrentVersion = llformat("%s %s",
- gSavedSettings.getString("VersionChannelName").c_str(),
- LLVersionInfo::getVersion().c_str());
+ // Initialize updater service (now that we have an io pump)
+ initUpdater();
+ if(isQuitting())
+ {
+ // Early out here because updater set the quitting flag.
+ return true;
+ }
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
@@ -799,6 +806,9 @@ bool LLAppViewer::init()
return 1;
}
+ // Initialize the repeater service.
+ LLMainLoopRepeater::instance().start();
+
//
// Initialize the window
//
@@ -895,7 +905,8 @@ bool LLAppViewer::init()
gDebugInfo["GraphicsCard"] = LLFeatureManager::getInstance()->getGPUString();
// Save the current version to the prefs file
- gSavedSettings.setString("LastRunVersion", gCurrentVersion);
+ gSavedSettings.setString("LastRunVersion",
+ LLVersionInfo::getChannelAndVersion());
gSimLastTime = gRenderStartTime.getElapsedTimeF32();
gSimFrames = (F32)gFrameCount;
@@ -970,7 +981,7 @@ bool LLAppViewer::mainLoop()
gServicePump = new LLPumpIO(gAPRPoolp);
LLHTTPClient::setPump(*gServicePump);
LLCurl::setCAFile(gDirUtilp->getCAFile());
-
+
// Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated.
LLVoiceChannel::initClass();
@@ -1353,11 +1364,14 @@ bool LLAppViewer::cleanup()
llinfos << "Cleaning Up" << llendflush;
// Must clean up texture references before viewer window is destroyed.
- LLHUDManager::getInstance()->updateEffects();
- LLHUDObject::updateAll();
- LLHUDManager::getInstance()->cleanupEffects();
- LLHUDObject::cleanupHUDObjects();
- llinfos << "HUD Objects cleaned up" << llendflush;
+ if(LLHUDManager::instanceExists())
+ {
+ LLHUDManager::getInstance()->updateEffects();
+ LLHUDObject::updateAll();
+ LLHUDManager::getInstance()->cleanupEffects();
+ LLHUDObject::cleanupHUDObjects();
+ llinfos << "HUD Objects cleaned up" << llendflush;
+ }
LLKeyframeDataCache::clear();
@@ -1369,8 +1383,10 @@ bool LLAppViewer::cleanup()
// Note: this is where gWorldMap used to be deleted.
// Note: this is where gHUDManager used to be deleted.
- LLHUDManager::getInstance()->shutdownClass();
-
+ if(LLHUDManager::instanceExists())
+ {
+ LLHUDManager::getInstance()->shutdownClass();
+ }
delete gAssetStorage;
gAssetStorage = NULL;
@@ -1666,7 +1682,10 @@ bool LLAppViewer::cleanup()
#ifndef LL_RELEASE_FOR_DOWNLOAD
llinfos << "Auditing VFS" << llendl;
- gVFS->audit();
+ if(gVFS)
+ {
+ gVFS->audit();
+ }
#endif
llinfos << "Misc Cleanup" << llendflush;
@@ -1707,6 +1726,8 @@ bool LLAppViewer::cleanup()
llinfos << "File launched." << llendflush;
}
+ LLMainLoopRepeater::instance().stop();
+
ll_close_fail_log();
llinfos << "Goodbye!" << llendflush;
@@ -1953,8 +1974,6 @@ bool LLAppViewer::initConfiguration()
gSavedSettings.setString("ClientSettingsFile",
gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Global")));
- gSavedSettings.setString("VersionChannelName", LLVersionInfo::getChannel());
-
#ifndef LL_RELEASE_FOR_DOWNLOAD
// provide developer build only overrides for these control variables that are not
// persisted to settings.xml
@@ -2095,6 +2114,11 @@ bool LLAppViewer::initConfiguration()
}
}
+ if(clp.hasOption("channel"))
+ {
+ LLVersionInfo::resetChannel(clp.getOption("channel")[0]);
+ }
+
// If we have specified crash on startup, set the global so we'll trigger the crash at the right time
if(clp.hasOption("crashonstartup"))
@@ -2364,6 +2388,58 @@ bool LLAppViewer::initConfiguration()
return true; // Config was successful.
}
+namespace {
+ // *TODO - decide if there's a better place for this function.
+ // do we need a file llupdaterui.cpp or something? -brad
+ bool notify_update(LLSD const & evt)
+ {
+ switch (evt["type"].asInteger())
+ {
+ case LLUpdaterService::DOWNLOAD_COMPLETE:
+ LLNotificationsUtil::add("DownloadBackground");
+ break;
+ case LLUpdaterService::INSTALL_ERROR:
+ LLNotificationsUtil::add("FailedUpdateInstall");
+ break;
+ default:
+ llinfos << "unhandled update event " << evt << llendl;
+ break;
+ }
+
+ // let others also handle this event by default
+ return false;
+ }
+};
+
+void LLAppViewer::initUpdater()
+{
+ // Initialize the updater service.
+ // Generate URL to the udpater service
+ // Get Channel
+ // Get Version
+ std::string url = gSavedSettings.getString("UpdaterServiceURL");
+ std::string channel = LLVersionInfo::getChannel();
+ std::string version = LLVersionInfo::getVersion();
+ std::string protocol_version = gSavedSettings.getString("UpdaterServiceProtocolVersion");
+ std::string service_path = gSavedSettings.getString("UpdaterServicePath");
+ U32 check_period = gSavedSettings.getU32("UpdaterServiceCheckPeriod");
+
+ mUpdater->setAppExitCallback(boost::bind(&LLAppViewer::forceQuit, this));
+ mUpdater->initialize(protocol_version,
+ url,
+ service_path,
+ channel,
+ version);
+ mUpdater->setCheckPeriod(check_period);
+ if(gSavedSettings.getBOOL("UpdaterServiceActive"))
+ {
+ bool install_if_ready = true;
+ mUpdater->startChecking(install_if_ready);
+ }
+
+ LLEventPump & updater_pump = LLEventPumps::instance().obtain(LLUpdaterService::pumpName());
+ updater_pump.listen("notify_update", &notify_update);
+}
void LLAppViewer::checkForCrash(void)
{
@@ -2524,15 +2600,18 @@ void LLAppViewer::cleanupSavedSettings()
// save window position if not maximized
// as we don't track it in callbacks
- BOOL maximized = gViewerWindow->mWindow->getMaximized();
- if (!maximized)
+ if(NULL != gViewerWindow)
{
- LLCoordScreen window_pos;
-
- if (gViewerWindow->mWindow->getPosition(&window_pos))
+ BOOL maximized = gViewerWindow->mWindow->getMaximized();
+ if (!maximized)
{
- gSavedSettings.setS32("WindowX", window_pos.mX);
- gSavedSettings.setS32("WindowY", window_pos.mY);
+ LLCoordScreen window_pos;
+
+ if (gViewerWindow->mWindow->getPosition(&window_pos))
+ {
+ gSavedSettings.setS32("WindowX", window_pos.mX);
+ gSavedSettings.setS32("WindowY", window_pos.mY);
+ }
}
}
@@ -2555,7 +2634,7 @@ void LLAppViewer::writeSystemInfo()
{
gDebugInfo["SLLog"] = LLError::logFileName();
- gDebugInfo["ClientInfo"]["Name"] = gSavedSettings.getString("VersionChannelName");
+ gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel();
gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor();
gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor();
gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch();
@@ -2658,7 +2737,7 @@ void LLAppViewer::handleViewerCrash()
//We already do this in writeSystemInfo(), but we do it again here to make /sure/ we have a version
//to check against no matter what
- gDebugInfo["ClientInfo"]["Name"] = gSavedSettings.getString("VersionChannelName");
+ gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel();
gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor();
gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor();
@@ -4271,7 +4350,10 @@ void LLAppViewer::disconnectViewer()
// This is where we used to call gObjectList.destroy() and then delete gWorldp.
// Now we just ask the LLWorld singleton to cleanly shut down.
- LLWorld::getInstance()->destroyClass();
+ if(LLWorld::instanceExists())
+ {
+ LLWorld::getInstance()->destroyClass();
+ }
// call all self-registered classes
LLDestroyClassList::instance().fireCallbacks();
@@ -4385,7 +4467,7 @@ void LLAppViewer::handleLoginComplete()
initMainloopTimeout("Mainloop Init");
// Store some data to DebugInfo in case of a freeze.
- gDebugInfo["ClientInfo"]["Name"] = gSavedSettings.getString("VersionChannelName");
+ gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel();
gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor();
gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor();
@@ -4491,7 +4573,7 @@ void LLAppViewer::launchUpdater()
// *TODO change userserver to be grid on both viewer and sim, since
// userserver no longer exists.
query_map["userserver"] = LLGridManager::getInstance()->getGridLabel();
- query_map["channel"] = gSavedSettings.getString("VersionChannelName");
+ query_map["channel"] = LLVersionInfo::getChannel();
// *TODO constantize this guy
// *NOTE: This URL is also used in win_setup/lldownloader.cpp
LLURI update_url = LLURI::buildHTTP("secondlife.com", 80, "update.php", query_map);
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index a14ab4362f..aa4256a2bd 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -39,7 +39,7 @@ class LLTextureCache;
class LLImageDecodeThread;
class LLTextureFetch;
class LLWatchdogTimeout;
-class LLCommandLineParser;
+class LLUpdaterService;
struct apr_dso_handle_t;
@@ -186,7 +186,7 @@ private:
bool initThreads(); // Initialize viewer threads, return false on failure.
bool initConfiguration(); // Initialize settings from the command line/config file.
-
+ void initUpdater(); // Initialize the updater service.
bool initCache(); // Initialize local client cache.
@@ -264,7 +264,14 @@ private:
U32 mAvailPhysicalMemInKB ;
U32 mAvailVirtualMemInKB ;
+
+ boost::scoped_ptr<LLUpdaterService> mUpdater;
+
+ //---------------------------------------------
+ //*NOTE: Mani - legacy updater stuff
+ // Still useable?
public:
+
//some information for updater
typedef struct
{
@@ -274,6 +281,7 @@ public:
static LLUpdaterInfo *sUpdaterInfo ;
void launchUpdater();
+ //---------------------------------------------
};
// consts from viewer.h
diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp
index 29c2b7565e..6ccb5aaf54 100644
--- a/indra/newview/llbottomtray.cpp
+++ b/indra/newview/llbottomtray.cpp
@@ -1365,20 +1365,33 @@ void LLBottomTray::processExtendButtons(S32& available_width)
processExtendButton(*it, available_width);
}
+ const S32 chiclet_panel_width = mChicletPanel->getParent()->getRect().getWidth();
+ static const S32 chiclet_panel_min_width = mChicletPanel->getMinWidth();
+ const S32 available_width_chiclet = chiclet_panel_width - chiclet_panel_min_width;
+
// then try to extend Speak button
- if (available_width > 0)
+ if (available_width > 0 || available_width_chiclet > 0)
{
S32 panel_max_width = mObjectDefaultWidthMap[RS_BUTTON_SPEAK];
S32 panel_width = mSpeakPanel->getRect().getWidth();
S32 possible_extend_width = panel_max_width - panel_width;
- if (possible_extend_width >= 0 && possible_extend_width <= available_width) // HACK: this button doesn't change size so possible_extend_width will be 0
+
+ if (possible_extend_width >= 0 && possible_extend_width <= available_width + available_width_chiclet) // HACK: this button doesn't change size so possible_extend_width will be 0
{
mSpeakBtn->setLabelVisible(true);
mSpeakPanel->reshape(panel_max_width, mSpeakPanel->getRect().getHeight());
log(mSpeakBtn, "speak button is extended");
- available_width -= possible_extend_width;
-
+ if( available_width > possible_extend_width)
+ {
+ available_width -= possible_extend_width;
+ }
+ else
+ {
+ S32 required_width = possible_extend_width - available_width;
+ available_width = 0;
+ mChicletPanel->getParent()->reshape(mChicletPanel->getParent()->getRect().getWidth() - required_width, mChicletPanel->getParent()->getRect().getHeight());
+ }
lldebugs << "Extending Speak button panel: " << mSpeakPanel->getName()
<< ", extended width: " << possible_extend_width
<< ", rest width to process: " << available_width
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index 8f385160e9..885d553524 100644
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -1092,9 +1092,11 @@ LLChicletPanel::LLChicletPanel(const Params&p)
LLChicletPanel::~LLChicletPanel()
{
- LLTransientFloaterMgr::getInstance()->removeControlView(mLeftScrollButton);
- LLTransientFloaterMgr::getInstance()->removeControlView(mRightScrollButton);
-
+ if(LLTransientFloaterMgr::instanceExists())
+ {
+ LLTransientFloaterMgr::getInstance()->removeControlView(mLeftScrollButton);
+ LLTransientFloaterMgr::getInstance()->removeControlView(mRightScrollButton);
+ }
}
void im_chiclet_callback(LLChicletPanel* panel, const LLSD& data){
diff --git a/indra/newview/llcolorswatch.cpp b/indra/newview/llcolorswatch.cpp
index e7634ff0f4..4a1ba6f1b5 100644
--- a/indra/newview/llcolorswatch.cpp
+++ b/indra/newview/llcolorswatch.cpp
@@ -195,7 +195,9 @@ BOOL LLColorSwatchCtrl::handleMouseUp(S32 x, S32 y, MASK mask)
// assumes GL state is set for 2D
void LLColorSwatchCtrl::draw()
{
- F32 alpha = getDrawContext().mAlpha;
+ // If we're in a focused floater, don't apply the floater's alpha to the color swatch (STORM-676).
+ F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
+
mBorder->setKeyboardFocusHighlight(hasFocus());
// Draw border
LLRect border( 0, getRect().getHeight(), getRect().getWidth(), mLabelHeight );
@@ -207,19 +209,29 @@ void LLColorSwatchCtrl::draw()
// Check state
if ( mValid )
{
+ if (!mColor.isOpaque())
+ {
+ // Draw checker board.
+ gl_rect_2d_checkerboard(interior, alpha);
+ }
+
// Draw the color swatch
- gl_rect_2d_checkerboard( interior );
- gl_rect_2d(interior, mColor, TRUE);
- LLColor4 opaque_color = mColor;
- opaque_color.mV[VALPHA] = 1.f;
- gGL.color4fv(opaque_color.mV);
- if (mAlphaGradientImage.notNull())
+ gl_rect_2d(interior, mColor % alpha, TRUE);
+
+ if (!mColor.isOpaque())
{
- gGL.pushMatrix();
+ // Draw semi-transparent center area in filled with mColor.
+ LLColor4 opaque_color = mColor;
+ opaque_color.mV[VALPHA] = alpha;
+ gGL.color4fv(opaque_color.mV);
+ if (mAlphaGradientImage.notNull())
{
- mAlphaGradientImage->draw(interior, mColor);
+ gGL.pushMatrix();
+ {
+ mAlphaGradientImage->draw(interior, mColor % alpha);
+ }
+ gGL.popMatrix();
}
- gGL.popMatrix();
}
}
else
diff --git a/indra/newview/llcurrencyuimanager.cpp b/indra/newview/llcurrencyuimanager.cpp
index 2b92b228b3..b4a1457f47 100644
--- a/indra/newview/llcurrencyuimanager.cpp
+++ b/indra/newview/llcurrencyuimanager.cpp
@@ -166,7 +166,7 @@ void LLCurrencyUIManager::Impl::updateCurrencyInfo()
gAgent.getSecureSessionID().asString());
keywordArgs.appendString("language", LLUI::getLanguage());
keywordArgs.appendInt("currencyBuy", mUserCurrencyBuy);
- keywordArgs.appendString("viewerChannel", gSavedSettings.getString("VersionChannelName"));
+ keywordArgs.appendString("viewerChannel", LLVersionInfo::getChannel());
keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::getMajor());
keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::getMinor());
keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::getPatch());
@@ -241,7 +241,7 @@ void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password)
{
keywordArgs.appendString("password", password);
}
- keywordArgs.appendString("viewerChannel", gSavedSettings.getString("VersionChannelName"));
+ keywordArgs.appendString("viewerChannel", LLVersionInfo::getChannel());
keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::getMajor());
keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::getMinor());
keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::getPatch());
diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp
index 135137069c..8ae3ccbae3 100644
--- a/indra/newview/llfloaterabout.cpp
+++ b/indra/newview/llfloaterabout.cpp
@@ -213,7 +213,7 @@ LLSD LLFloaterAbout::getInfo()
info["VIEWER_VERSION_STR"] = LLVersionInfo::getVersion();
info["BUILD_DATE"] = __DATE__;
info["BUILD_TIME"] = __TIME__;
- info["CHANNEL"] = gSavedSettings.getString("VersionChannelName");
+ info["CHANNEL"] = LLVersionInfo::getChannel();
info["VIEWER_RELEASE_NOTES_URL"] = get_viewer_release_notes_url();
@@ -291,7 +291,7 @@ static std::string get_viewer_release_notes_url()
std::string url = LLTrans::getString("RELEASE_NOTES_BASE_URL");
if (! LLStringUtil::endsWith(url, "/"))
url += "/";
- url += gSavedSettings.getString("VersionChannelName") + "/";
+ url += LLVersionInfo::getChannel() + "/";
url += LLVersionInfo::getShortVersion();
return LLWeb::escapeURL(url);
}
diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp
index 69f1774ff8..659e52271a 100644
--- a/indra/newview/llfloatercolorpicker.cpp
+++ b/indra/newview/llfloatercolorpicker.cpp
@@ -472,6 +472,12 @@ void LLFloaterColorPicker::onMouseCaptureLost()
setMouseDownInLumRegion(FALSE);
}
+F32 LLFloaterColorPicker::getSwatchTransparency()
+{
+ // If the floater is focused, don't apply its alpha to the color swatch (STORM-676).
+ return getTransparencyType() == TT_ACTIVE ? 1.f : LLFloater::getCurrentTransparency();
+}
+
//////////////////////////////////////////////////////////////////////////////
//
void LLFloaterColorPicker::draw()
@@ -533,8 +539,10 @@ void LLFloaterColorPicker::draw()
// base floater stuff
LLFloater::draw ();
+ const F32 alpha = getSwatchTransparency();
+
// draw image for RGB area (not really RGB but you'll see what I mean...
- gl_draw_image ( mRGBViewerImageLeft, mRGBViewerImageTop - mRGBViewerImageHeight, mRGBImage, LLColor4::white );
+ gl_draw_image ( mRGBViewerImageLeft, mRGBViewerImageTop - mRGBViewerImageHeight, mRGBImage, LLColor4::white % alpha);
// update 'cursor' into RGB Section
S32 xPos = ( S32 ) ( ( F32 )mRGBViewerImageWidth * getCurH () ) - 8;
@@ -556,7 +564,7 @@ void LLFloaterColorPicker::draw()
mRGBViewerImageTop - mRGBViewerImageHeight,
mRGBViewerImageLeft + mRGBViewerImageWidth + 1,
mRGBViewerImageTop,
- LLColor4 ( 0.0f, 0.0f, 0.0f, 1.0f ),
+ LLColor4 ( 0.0f, 0.0f, 0.0f, alpha ),
FALSE );
// draw luminance slider
@@ -569,7 +577,7 @@ void LLFloaterColorPicker::draw()
mLumRegionTop - mLumRegionHeight + y,
mLumRegionLeft + mLumRegionWidth,
mLumRegionTop - mLumRegionHeight + y - 1,
- LLColor4 ( rValSlider, gValSlider, bValSlider, 1.0f ) );
+ LLColor4 ( rValSlider, gValSlider, bValSlider, alpha ) );
}
@@ -594,7 +602,7 @@ void LLFloaterColorPicker::draw()
mSwatchRegionTop - mSwatchRegionHeight,
mSwatchRegionLeft + mSwatchRegionWidth,
mSwatchRegionTop,
- LLColor4 ( getCurR (), getCurG (), getCurB (), 1.0f ),
+ LLColor4 ( getCurR (), getCurG (), getCurB (), alpha ),
TRUE );
// draw selected color swatch outline
@@ -634,6 +642,7 @@ const LLColor4& LLFloaterColorPicker::getComplimentaryColor ( const LLColor4& ba
void LLFloaterColorPicker::drawPalette ()
{
S32 curEntry = 0;
+ const F32 alpha = getSwatchTransparency();
for ( S32 y = 0; y < numPaletteRows; ++y )
{
@@ -648,7 +657,7 @@ void LLFloaterColorPicker::drawPalette ()
// draw palette entry color
if ( mPalette [ curEntry ] )
{
- gl_rect_2d ( x1 + 2, y1 - 2, x2 - 2, y2 + 2, *mPalette [ curEntry++ ], TRUE );
+ gl_rect_2d ( x1 + 2, y1 - 2, x2 - 2, y2 + 2, *mPalette [ curEntry++ ] % alpha, TRUE );
gl_rect_2d ( x1 + 1, y1 - 1, x2 - 1, y2 + 1, LLColor4 ( 0.0f, 0.0f, 0.0f, 1.0f ), FALSE );
}
}
diff --git a/indra/newview/llfloatercolorpicker.h b/indra/newview/llfloatercolorpicker.h
index 110fa43b9c..8e387c4f7c 100644
--- a/indra/newview/llfloatercolorpicker.h
+++ b/indra/newview/llfloatercolorpicker.h
@@ -55,6 +55,7 @@ class LLFloaterColorPicker
virtual BOOL handleMouseUp ( S32 x, S32 y, MASK mask );
virtual BOOL handleHover ( S32 x, S32 y, MASK mask );
virtual void onMouseCaptureLost();
+ virtual F32 getSwatchTransparency();
// implicit methods
void createUI ();
diff --git a/indra/newview/llfloaterevent.cpp b/indra/newview/llfloaterevent.cpp
index 0b5ac8e798..a6dafda3e6 100644
--- a/indra/newview/llfloaterevent.cpp
+++ b/indra/newview/llfloaterevent.cpp
@@ -117,8 +117,3 @@ void LLFloaterEvent::setEventID(const U32 event_id)
}
}
-
-void LLFloaterEvent::draw()
-{
- LLPanel::draw();
-}
diff --git a/indra/newview/llfloaterevent.h b/indra/newview/llfloaterevent.h
index b1963309da..ed90055d95 100644
--- a/indra/newview/llfloaterevent.h
+++ b/indra/newview/llfloaterevent.h
@@ -43,7 +43,6 @@ public:
/*virtual*/ ~LLFloaterEvent();
/*virtual*/ BOOL postBuild();
- /*virtual*/ void draw();
void setEventID(const U32 event_id);
diff --git a/indra/newview/llfloatergroups.cpp b/indra/newview/llfloatergroups.cpp
index 234a09d157..d84364a68a 100644
--- a/indra/newview/llfloatergroups.cpp
+++ b/indra/newview/llfloatergroups.cpp
@@ -41,6 +41,7 @@
#include "llbutton.h"
#include "llgroupactions.h"
#include "llscrolllistctrl.h"
+#include "llstartup.h"
#include "lltextbox.h"
#include "lluictrlfactory.h"
#include "lltrans.h"
@@ -171,7 +172,7 @@ void LLPanelGroups::reset()
group_list->operateOnAll(LLCtrlListInterface::OP_DELETE);
}
getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d",gAgent.mGroups.count()));
- getChild<LLUICtrl>("groupcount")->setTextArg("[MAX]", llformat("%d",MAX_AGENT_GROUPS));
+ getChild<LLUICtrl>("groupcount")->setTextArg("[MAX]", llformat("%d",gMaxAgentGroups));
init_group_list(getChild<LLScrollListCtrl>("group list"), gAgent.getGroupID());
enableButtons();
@@ -182,7 +183,7 @@ BOOL LLPanelGroups::postBuild()
childSetCommitCallback("group list", onGroupList, this);
getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d",gAgent.mGroups.count()));
- getChild<LLUICtrl>("groupcount")->setTextArg("[MAX]", llformat("%d",MAX_AGENT_GROUPS));
+ getChild<LLUICtrl>("groupcount")->setTextArg("[MAX]", llformat("%d",gMaxAgentGroups));
LLScrollListCtrl *list = getChild<LLScrollListCtrl>("group list");
if (list)
diff --git a/indra/newview/llfloaterpostcard.cpp b/indra/newview/llfloaterpostcard.cpp
index e8e9f76912..f0c9d52ccd 100644
--- a/indra/newview/llfloaterpostcard.cpp
+++ b/indra/newview/llfloaterpostcard.cpp
@@ -128,6 +128,8 @@ void LLFloaterPostcard::draw()
if(!isMinimized() && mViewerImage.notNull() && mJPEGImage.notNull())
{
+ // Force the texture to be 100% opaque when the floater is focused.
+ F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
LLRect rect(getRect());
// first set the max extents of our preview
@@ -149,7 +151,7 @@ void LLFloaterPostcard::draw()
}
{
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gl_rect_2d(rect, LLColor4(0.f, 0.f, 0.f, 1.f));
+ gl_rect_2d(rect, LLColor4(0.f, 0.f, 0.f, 1.f) % alpha);
rect.stretch(-1);
}
{
@@ -164,7 +166,7 @@ void LLFloaterPostcard::draw()
rect.getWidth(),
rect.getHeight(),
mViewerImage.get(),
- LLColor4::white);
+ LLColor4::white % alpha);
}
glMatrixMode(GL_TEXTURE);
glPopMatrix();
@@ -361,9 +363,7 @@ void LLFloaterPostcard::sendPostcard()
{
gAssetStorage->storeAssetData(mTransactionID, LLAssetType::AT_IMAGE_JPEG, &uploadCallback, (void *)this, FALSE);
}
-
- // give user feedback of the event
- gViewerWindow->playSnapshotAnimAndSound();
+
LLUploadDialog::modalUploadDialog(getString("upload_message"));
// don't destroy the window until the upload is done
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index ac940f4f77..6a7b5171b5 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -283,6 +283,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
: LLFloater(key),
mGotPersonalInfo(false),
mOriginalIMViaEmail(false),
+ mLanguageChanged(false),
mDoubleClickActionDirty(false)
{
//Build Floater is now Called from LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>);
@@ -351,6 +352,8 @@ BOOL LLFloaterPreference::postBuild()
std::string cache_location = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "");
setCacheLocation(cache_location);
+ getChild<LLComboBox>("language_combobox")->setCommitCallback(boost::bind(&LLFloaterPreference::onLanguageChange, this));
+
// if floater is opened before login set default localized busy message
if (LLStartUp::getStartupState() < STATE_STARTED)
{
@@ -570,6 +573,9 @@ void LLFloaterPreference::onOpen(const LLSD& key)
getChildView("maturity_desired_combobox")->setVisible( false);
}
+ // Forget previous language changes.
+ mLanguageChanged = false;
+
// Display selected maturity icons.
onChangeMaturity();
@@ -727,6 +733,18 @@ void LLFloaterPreference::onClickBrowserClearCache()
LLNotificationsUtil::add("ConfirmClearBrowserCache", LLSD(), LLSD(), callback_clear_browser_cache);
}
+// Called when user changes language via the combobox.
+void LLFloaterPreference::onLanguageChange()
+{
+ // Let the user know that the change will only take effect after restart.
+ // Do it only once so that we're not too irritating.
+ if (!mLanguageChanged)
+ {
+ LLNotificationsUtil::add("ChangeLanguage");
+ mLanguageChanged = true;
+ }
+}
+
void LLFloaterPreference::onClickSetCache()
{
std::string cur_name(gSavedSettings.getString("CacheLocation"));
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 46f50d9a4d..bb871e7e25 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -83,6 +83,7 @@ protected:
void onBtnApply();
void onClickBrowserClearCache();
+ void onLanguageChange();
// set value of "BusyResponseChanged" in account settings depending on whether busy response
// string differs from default after user changes.
@@ -158,6 +159,7 @@ private:
bool mDoubleClickActionDirty;
bool mGotPersonalInfo;
bool mOriginalIMViaEmail;
+ bool mLanguageChanged;
bool mOriginalHideOnlineStatus;
std::string mDirectoryVisibility;
diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp
index 51ee38bd65..cad54cd158 100644
--- a/indra/newview/llfloatersnapshot.cpp
+++ b/indra/newview/llfloatersnapshot.cpp
@@ -1004,7 +1004,6 @@ void LLSnapshotLivePreview::saveTexture()
LLFloaterPerms::getEveryonePerms(),
"Snapshot : " + pos_string,
callback, expected_upload_cost, userdata);
- gViewerWindow->playSnapshotAnimAndSound();
}
else
{
@@ -1026,10 +1025,6 @@ BOOL LLSnapshotLivePreview::saveLocal()
mDataSize = 0;
updateSnapshot(FALSE, FALSE);
- if(success)
- {
- gViewerWindow->playSnapshotAnimAndSound();
- }
return success;
}
@@ -1049,8 +1044,6 @@ void LLSnapshotLivePreview::saveWeb()
LLLandmarkActions::getRegionNameAndCoordsFromPosGlobal(gAgentCamera.getCameraPositionGlobal(),
boost::bind(&LLSnapshotLivePreview::regionNameCallback, this, jpg, metadata, _1, _2, _3, _4));
-
- gViewerWindow->playSnapshotAnimAndSound();
}
void LLSnapshotLivePreview::regionNameCallback(LLImageJPEG* snapshot, LLSD& metadata, const std::string& name, S32 x, S32 y, S32 z)
@@ -1540,6 +1533,8 @@ void LLFloaterSnapshot::Impl::onClickNewSnapshot(void* data)
if (previewp && view)
{
previewp->updateSnapshot(TRUE);
+
+ gViewerWindow->playSnapshotAnimAndSound();
}
}
@@ -2189,9 +2184,11 @@ void LLFloaterSnapshot::draw()
S32 offset_y = thumbnail_rect.mBottom + (thumbnail_rect.getHeight() - previewp->getThumbnailHeight()) / 2 ;
glMatrixMode(GL_MODELVIEW);
+ // Apply floater transparency to the texture unless the floater is focused.
+ F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
gl_draw_scaled_image(offset_x, offset_y,
previewp->getThumbnailWidth(), previewp->getThumbnailHeight(),
- previewp->getThumbnailImage(), LLColor4::white);
+ previewp->getThumbnailImage(), LLColor4::white % alpha);
previewp->drawPreviewRect(offset_x, offset_y) ;
}
@@ -2209,6 +2206,8 @@ void LLFloaterSnapshot::onOpen(const LLSD& key)
gSnapshotFloaterView->setEnabled(TRUE);
gSnapshotFloaterView->setVisible(TRUE);
gSnapshotFloaterView->adjustToFitScreen(this, FALSE);
+
+ gViewerWindow->playSnapshotAnimAndSound();
}
void LLFloaterSnapshot::onClose(bool app_quitting)
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 3578c98622..f5f59d5973 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -279,9 +279,27 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string&
void LLIMModel::LLIMSession::onAdHocNameCache(const LLAvatarName& av_name)
{
- LLStringUtil::format_map_t args;
- args["[AGENT_NAME]"] = av_name.getCompleteName();
- LLTrans::findString(mName, "conference-title-incoming", args);
+ 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);
+ }
+ }
+ else
+ {
+ LLStringUtil::format_map_t args;
+ args["[AGENT_NAME]"] = av_name.getCompleteName();
+ LLTrans::findString(mName, "conference-title-incoming", args);
+ }
}
void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction)
@@ -555,7 +573,12 @@ void LLIMModel::LLIMSession::buildHistoryFileName()
//ad-hoc requires sophisticated chat history saving schemes
if (isAdHoc())
{
- //in case of outgoing ad-hoc sessions
+ /* in case of outgoing ad-hoc sessions we need to make specilized names
+ * if this naming system is ever changed then the filtering definitions in
+ * lllogchat.cpp need to be change acordingly so that the filtering for the
+ * date stamp code introduced in STORM-102 will work properly and not add
+ * a date stamp to the Ad-hoc conferences.
+ */
if (mInitialTargetIDs.size())
{
std::set<LLUUID> sorted_uuids(mInitialTargetIDs.begin(), mInitialTargetIDs.end());
@@ -2165,7 +2188,7 @@ void LLIncomingCallDialog::processCallResponse(S32 response)
LLAvatarName av_name;
if (LLAvatarNameCache::get(caller_id, &av_name))
{
- correct_session_name = av_name.mDisplayName + " (" + av_name.mUsername + ")";
+ correct_session_name = av_name.getCompleteName();
correct_session_name.append(ADHOC_NAME_SUFFIX);
}
}
diff --git a/indra/newview/llinventorylistitem.cpp b/indra/newview/llinventorylistitem.cpp
index 225d0288a9..3e0849a795 100644
--- a/indra/newview/llinventorylistitem.cpp
+++ b/indra/newview/llinventorylistitem.cpp
@@ -97,7 +97,8 @@ void LLPanelInventoryListItemBase::draw()
LLRect separator_rect = getLocalRect();
separator_rect.mTop = separator_rect.mBottom;
separator_rect.mBottom -= mSeparatorImage->getHeight();
- mSeparatorImage->draw(separator_rect);
+ F32 alpha = getCurrentTransparency();
+ mSeparatorImage->draw(separator_rect, UI_VERTEX_COLOR % alpha);
}
LLPanel::draw();
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp
index 2fb5ba82ba..0121bbb1ed 100644
--- a/indra/newview/lllogchat.cpp
+++ b/indra/newview/lllogchat.cpp
@@ -89,6 +89,16 @@ 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}");
+
//is used to parse complex object names like "Xstreet SL Terminal v2.2.5 st"
const static std::string NAME_TEXT_DIVIDER(": ");
@@ -182,25 +192,37 @@ private:
//static
std::string LLLogChat::makeLogFileName(std::string filename)
{
- if( gSavedPerAccountSettings.getBOOL("LogFileNamewithDate") )
+ /**
+ * Testing for in bound and out bound ad-hoc file names
+ * if it is then skip date stamping.
+ **/
+ //LL_INFOS("") << "Befor:" << filename << LL_ENDL;/* uncomment if you want to verify step, delete on commit */
+ boost::match_results<std::string::const_iterator> matches;
+ bool inboundConf = boost::regex_match(filename, matches, INBOUND_CONFERENCE);
+ bool outboundConf = boost::regex_match(filename, matches, OUTBOUND_CONFERENCE);
+ if (!(inboundConf || outboundConf))
{
- time_t now;
- time(&now);
- char dbuffer[20]; /* Flawfinder: ignore */
- if (filename == "chat")
+ if( gSavedPerAccountSettings.getBOOL("LogFileNamewithDate") )
{
- strftime(dbuffer, 20, "-%Y-%m-%d", localtime(&now));
- }
- else
- {
- strftime(dbuffer, 20, "-%Y-%m", localtime(&now));
+ time_t now;
+ time(&now);
+ char dbuffer[20]; /* Flawfinder: ignore */
+ if (filename == "chat")
+ {
+ strftime(dbuffer, 20, "-%Y-%m-%d", localtime(&now));
+ }
+ else
+ {
+ strftime(dbuffer, 20, "-%Y-%m", localtime(&now));
+ }
+ filename += dbuffer;
}
- filename += dbuffer;
}
+ //LL_INFOS("") << "After:" << filename << LL_ENDL;/* uncomment if you want to verify step, delete on commit */
filename = cleanFileName(filename);
filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS,filename);
filename += ".txt";
- //LL_INFOS("") << "Current:" << filename << LL_ENDL;/* uncomment if you want to verify step, delete on commit */
+ //LL_INFOS("") << "Full:" << filename << LL_ENDL;/* uncomment if you want to verify step, delete on commit */
return filename;
}
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 029e700c4c..52ce932241 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -42,6 +42,7 @@
// newview
#include "llviewernetwork.h"
#include "llviewercontrol.h"
+#include "llversioninfo.h"
#include "llslurl.h"
#include "llstartup.h"
#include "llfloaterreg.h"
@@ -149,6 +150,7 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
requested_options.append("newuser-config");
requested_options.append("ui-config");
#endif
+ requested_options.append("max-agent-groups");
requested_options.append("map-server-url");
requested_options.append("voice-config");
requested_options.append("tutorial_setting");
@@ -181,8 +183,8 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
request_params["read_critical"] = false; // handleTOSResponse
request_params["last_exec_event"] = mLastExecEvent;
request_params["mac"] = hashed_unique_id_string;
- request_params["version"] = gCurrentVersion; // Includes channel name
- request_params["channel"] = gSavedSettings.getString("VersionChannelName");
+ request_params["version"] = LLVersionInfo::getChannelAndVersion(); // Includes channel name
+ request_params["channel"] = LLVersionInfo::getChannel();
request_params["id0"] = mSerialNumber;
mRequestData.clear();
diff --git a/indra/newview/llmainlooprepeater.cpp b/indra/newview/llmainlooprepeater.cpp
new file mode 100644
index 0000000000..5c020e6d98
--- /dev/null
+++ b/indra/newview/llmainlooprepeater.cpp
@@ -0,0 +1,88 @@
+/**
+ * @file llmachineid.cpp
+ * @brief retrieves unique machine ids
+ *
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llapr.h"
+#include "llevents.h"
+#include "llmainlooprepeater.h"
+
+
+
+// LLMainLoopRepeater
+//-----------------------------------------------------------------------------
+
+
+LLMainLoopRepeater::LLMainLoopRepeater(void):
+ mQueue(0)
+{
+ ; // No op.
+}
+
+
+void LLMainLoopRepeater::start(void)
+{
+ if(mQueue != 0) return;
+
+ mQueue = new LLThreadSafeQueue<LLSD>(gAPRPoolp, 1024);
+ mMainLoopConnection = LLEventPumps::instance().
+ obtain("mainloop").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMainLoop, this, _1));
+ mRepeaterConnection = LLEventPumps::instance().
+ obtain("mainlooprepeater").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMessage, this, _1));
+}
+
+
+void LLMainLoopRepeater::stop(void)
+{
+ mMainLoopConnection.release();
+ mRepeaterConnection.release();
+
+ delete mQueue;
+ mQueue = 0;
+}
+
+
+bool LLMainLoopRepeater::onMainLoop(LLSD const &)
+{
+ LLSD message;
+ while(mQueue->tryPopBack(message)) {
+ std::string pump = message["pump"].asString();
+ if(pump.length() == 0 ) continue; // No pump.
+ LLEventPumps::instance().obtain(pump).post(message["payload"]);
+ }
+ return false;
+}
+
+
+bool LLMainLoopRepeater::onMessage(LLSD const & event)
+{
+ try {
+ mQueue->pushFront(event);
+ } catch(LLThreadSafeQueueError & e) {
+ llwarns << "could not repeat message (" << e.what() << ")" <<
+ event.asString() << LL_ENDL;
+ }
+ return false;
+}
diff --git a/indra/newview/llmainlooprepeater.h b/indra/newview/llmainlooprepeater.h
new file mode 100644
index 0000000000..f84c0ca94c
--- /dev/null
+++ b/indra/newview/llmainlooprepeater.h
@@ -0,0 +1,65 @@
+/**
+ * @file llmainlooprepeater.h
+ * @brief a service for repeating messages on the main loop.
+ *
+ * $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_LLMAINLOOPREPEATER_H
+#define LL_LLMAINLOOPREPEATER_H
+
+
+#include "llsd.h"
+#include "llthreadsafequeue.h"
+
+
+//
+// A service which creates the pump 'mainlooprepeater' to which any thread can
+// post a message that will be re-posted on the main loop.
+//
+// The posted message should contain two map elements: pump and payload. The
+// pump value is a string naming the pump to which the message should be
+// re-posted. The payload value is what will be posted to the designated pump.
+//
+class LLMainLoopRepeater:
+ public LLSingleton<LLMainLoopRepeater>
+{
+public:
+ LLMainLoopRepeater(void);
+
+ // Start the repeater service.
+ void start(void);
+
+ // Stop the repeater service.
+ void stop(void);
+
+private:
+ LLTempBoundListener mMainLoopConnection;
+ LLTempBoundListener mRepeaterConnection;
+ LLThreadSafeQueue<LLSD> * mQueue;
+
+ bool onMainLoop(LLSD const &);
+ bool onMessage(LLSD const & event);
+};
+
+
+#endif
diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp
index 6658e1d7e8..d38bb5aa4a 100644
--- a/indra/newview/llmoveview.cpp
+++ b/indra/newview/llmoveview.cpp
@@ -552,7 +552,7 @@ LLPanelStandStopFlying::LLPanelStandStopFlying() :
}
// static
-inline LLPanelStandStopFlying* LLPanelStandStopFlying::getInstance()
+LLPanelStandStopFlying* LLPanelStandStopFlying::getInstance()
{
static LLPanelStandStopFlying* panel = getStandStopFlyingPanel();
return panel;
diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp
index 180695e40b..572eeb8fc7 100644
--- a/indra/newview/llnearbychat.cpp
+++ b/indra/newview/llnearbychat.cpp
@@ -365,3 +365,16 @@ BOOL LLNearbyChat::handleMouseDown(S32 x, S32 y, MASK mask)
mChatHistory->setFocus(TRUE);
return LLDockableFloater::handleMouseDown(x, y, mask);
}
+
+void LLNearbyChat::draw()
+{
+ // *HACK: Update transparency type depending on whether our children have focus.
+ // This is needed because this floater is chrome and thus cannot accept focus, so
+ // the transparency type setting code from LLFloater::setFocus() isn't reached.
+ if (getTransparencyType() != TT_DEFAULT)
+ {
+ setTransparencyType(hasFocus() ? TT_ACTIVE : TT_INACTIVE);
+ }
+
+ LLDockableFloater::draw();
+}
diff --git a/indra/newview/llnearbychat.h b/indra/newview/llnearbychat.h
index 1e62910385..2ea79797f8 100644
--- a/indra/newview/llnearbychat.h
+++ b/indra/newview/llnearbychat.h
@@ -48,6 +48,7 @@ public:
bool onNearbyChatCheckContextMenuItem(const LLSD& userdata);
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+ virtual void draw();
// focus overrides
/*virtual*/ void onFocusLost();
diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp
index 57180f63b5..1249d5d856 100644
--- a/indra/newview/llpanelavatar.cpp
+++ b/indra/newview/llpanelavatar.cpp
@@ -34,6 +34,7 @@
#include "llcombobox.h"
#include "lldateutil.h" // ageFromDate()
#include "llimview.h"
+#include "llmenubutton.h"
#include "llnotificationsutil.h"
#include "lltexteditor.h"
#include "lltexturectrl.h"
@@ -479,7 +480,6 @@ BOOL LLPanelAvatarProfile::postBuild()
childSetCommitCallback("im",(boost::bind(&LLPanelAvatarProfile::onIMButtonClick,this)),NULL);
childSetCommitCallback("call",(boost::bind(&LLPanelAvatarProfile::onCallButtonClick,this)),NULL);
childSetCommitCallback("teleport",(boost::bind(&LLPanelAvatarProfile::onTeleportButtonClick,this)),NULL);
- childSetCommitCallback("overflow_btn", boost::bind(&LLPanelAvatarProfile::onOverflowButtonClicked, this), NULL);
childSetCommitCallback("share",(boost::bind(&LLPanelAvatarProfile::onShareButtonClick,this)),NULL);
childSetCommitCallback("show_on_map_btn", (boost::bind(
&LLPanelAvatarProfile::onMapButtonClick, this)), NULL);
@@ -500,7 +500,8 @@ BOOL LLPanelAvatarProfile::postBuild()
enable.add("Profile.EnableBlock", boost::bind(&LLPanelAvatarProfile::enableBlock, this));
enable.add("Profile.EnableUnblock", boost::bind(&LLPanelAvatarProfile::enableUnblock, this));
- mProfileMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_profile_overflow.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ LLToggleableMenu* profile_menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_profile_overflow.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ getChild<LLMenuButton>("overflow_btn")->setMenu(profile_menu, LLMenuButton::MP_TOP_RIGHT);
LLVoiceClient::getInstance()->addObserver((LLVoiceClientStatusObserver*)this);
@@ -752,23 +753,6 @@ void LLPanelAvatarProfile::onShareButtonClick()
//*TODO not implemented
}
-void LLPanelAvatarProfile::onOverflowButtonClicked()
-{
- if (!mProfileMenu->toggleVisibility())
- return;
-
- LLView* btn = getChild<LLView>("overflow_btn");
-
- if (mProfileMenu->getButtonRect().isEmpty())
- {
- mProfileMenu->setButtonRect(btn);
- }
- mProfileMenu->updateParent(LLMenuGL::sMenuContainer);
-
- LLRect rect = btn->getRect();
- LLMenuGL::showPopup(this, mProfileMenu, rect.mRight, rect.mTop);
-}
-
LLPanelAvatarProfile::~LLPanelAvatarProfile()
{
if(getAvatarId().notNull())
diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h
index 11c7716322..71d9d0a95a 100644
--- a/indra/newview/llpanelavatar.h
+++ b/indra/newview/llpanelavatar.h
@@ -34,7 +34,6 @@
class LLComboBox;
class LLLineEditor;
-class LLToggleableMenu;
enum EOnlineStatus
{
@@ -207,14 +206,11 @@ protected:
void onCallButtonClick();
void onTeleportButtonClick();
void onShareButtonClick();
- void onOverflowButtonClicked();
private:
typedef std::map< std::string,LLUUID> group_map_t;
group_map_t mGroups;
-
- LLToggleableMenu* mProfileMenu;
};
/**
diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp
index d25b8e0e02..e8c8273a9d 100644
--- a/indra/newview/llpanellandmarks.cpp
+++ b/indra/newview/llpanellandmarks.cpp
@@ -520,9 +520,6 @@ void LLLandmarksPanel::setParcelID(const LLUUID& parcel_id)
{
if (!parcel_id.isNull())
{
- //ext-4655, defensive. remove now incase this gets called twice without a remove
- LLRemoteParcelInfoProcessor::getInstance()->removeObserver(parcel_id, this);
-
LLRemoteParcelInfoProcessor::getInstance()->addObserver(parcel_id, this);
LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(parcel_id);
}
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index 467aefc60f..cf567fb208 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -230,7 +230,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
getChild<LLPanel>("login")->setDefaultBtn("connect_btn");
- std::string channel = gSavedSettings.getString("VersionChannelName");
+ std::string channel = LLVersionInfo::getChannel();
std::string version = llformat("%s (%d)",
LLVersionInfo::getShortVersion().c_str(),
LLVersionInfo::getBuild());
@@ -817,7 +817,7 @@ void LLPanelLogin::loadLoginPage()
LLVersionInfo::getShortVersion().c_str(),
LLVersionInfo::getBuild());
- char* curl_channel = curl_escape(gSavedSettings.getString("VersionChannelName").c_str(), 0);
+ char* curl_channel = curl_escape(LLVersionInfo::getChannel().c_str(), 0);
char* curl_version = curl_escape(version.c_str(), 0);
oStr << "&channel=" << curl_channel;
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 71c812efe2..54198d6aa4 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -231,7 +231,7 @@ public:
virtual void setActive(bool) {}
protected:
- void updateList()
+ void update()
{
mCallback();
}
@@ -239,6 +239,30 @@ protected:
callback_t mCallback;
};
+/**
+ * Update buttons on changes in our friend relations (STORM-557).
+ */
+class LLButtonsUpdater : public LLPanelPeople::Updater, public LLFriendObserver
+{
+public:
+ LLButtonsUpdater(callback_t cb)
+ : LLPanelPeople::Updater(cb)
+ {
+ LLAvatarTracker::instance().addObserver(this);
+ }
+
+ ~LLButtonsUpdater()
+ {
+ LLAvatarTracker::instance().removeObserver(this);
+ }
+
+ /*virtual*/ void changed(U32 mask)
+ {
+ (void) mask;
+ update();
+ }
+};
+
class LLAvatarListUpdater : public LLPanelPeople::Updater, public LLEventTimer
{
public:
@@ -306,7 +330,7 @@ public:
if (mMask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE))
{
- updateList();
+ update();
}
// Stop updates.
@@ -421,7 +445,7 @@ public:
if (val)
{
// update immediately and start regular updates
- updateList();
+ update();
mEventTimer.start();
}
else
@@ -433,7 +457,7 @@ public:
/*virtual*/ BOOL tick()
{
- updateList();
+ update();
return FALSE;
}
private:
@@ -450,7 +474,7 @@ public:
LLRecentListUpdater(callback_t cb)
: LLAvatarListUpdater(cb, 0)
{
- LLRecentPeople::instance().setChangedCallback(boost::bind(&LLRecentListUpdater::updateList, this));
+ LLRecentPeople::instance().setChangedCallback(boost::bind(&LLRecentListUpdater::update, this));
}
};
@@ -475,11 +499,13 @@ LLPanelPeople::LLPanelPeople()
mFriendListUpdater = new LLFriendListUpdater(boost::bind(&LLPanelPeople::updateFriendList, this));
mNearbyListUpdater = new LLNearbyListUpdater(boost::bind(&LLPanelPeople::updateNearbyList, this));
mRecentListUpdater = new LLRecentListUpdater(boost::bind(&LLPanelPeople::updateRecentList, this));
+ mButtonsUpdater = new LLButtonsUpdater(boost::bind(&LLPanelPeople::updateButtons, this));
mCommitCallbackRegistrar.add("People.addFriend", boost::bind(&LLPanelPeople::onAddFriendButtonClicked, this));
}
LLPanelPeople::~LLPanelPeople()
{
+ delete mButtonsUpdater;
delete mNearbyListUpdater;
delete mFriendListUpdater;
delete mRecentListUpdater;
@@ -1367,9 +1393,6 @@ void LLPanelPeople::onMoreButtonClicked()
void LLPanelPeople::onOpen(const LLSD& key)
{
std::string tab_name = key["people_panel_tab_name"];
- mFilterEditor -> clear();
- onFilterEdit("");
-
if (!tab_name.empty())
mTabContainer->selectTabByName(tab_name);
}
diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h
index 4412aed062..b496bb3779 100644
--- a/indra/newview/llpanelpeople.h
+++ b/indra/newview/llpanelpeople.h
@@ -152,6 +152,7 @@ private:
Updater* mFriendListUpdater;
Updater* mNearbyListUpdater;
Updater* mRecentListUpdater;
+ Updater* mButtonsUpdater;
LLMenuButton* mNearbyGearButton;
LLMenuButton* mFriendsGearButton;
diff --git a/indra/newview/llpanelpick.cpp b/indra/newview/llpanelpick.cpp
index 271728220c..44cca21a76 100644
--- a/indra/newview/llpanelpick.cpp
+++ b/indra/newview/llpanelpick.cpp
@@ -204,9 +204,6 @@ void LLPanelPickInfo::sendParcelInfoRequest()
{
if (mParcelId != mRequestedId)
{
- //ext-4655, remove now incase this gets called twice without a remove
- LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mRequestedId, this);
-
LLRemoteParcelInfoProcessor::getInstance()->addObserver(mParcelId, this);
LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(mParcelId);
diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp
index 9cbb512e70..4ae0c0eb12 100644
--- a/indra/newview/llpanelplaceinfo.cpp
+++ b/indra/newview/llpanelplaceinfo.cpp
@@ -128,10 +128,6 @@ void LLPanelPlaceInfo::sendParcelInfoRequest()
{
if (mParcelID != mRequestedID)
{
- //ext-4655, defensive. remove now incase this gets called twice without a remove
- //as panel never closes its ok atm (but wrong :)
- LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mRequestedID, this);
-
LLRemoteParcelInfoProcessor::getInstance()->addObserver(mParcelID, this);
LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(mParcelID);
diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp
index f0e60386b6..c524fd7059 100644
--- a/indra/newview/llpanelplaces.cpp
+++ b/indra/newview/llpanelplaces.cpp
@@ -39,6 +39,7 @@
#include "llfiltereditor.h"
#include "llfirstuse.h"
#include "llfloaterreg.h"
+#include "llmenubutton.h"
#include "llnotificationsutil.h"
#include "lltabcontainer.h"
#include "lltexteditor.h"
@@ -282,8 +283,8 @@ BOOL LLPanelPlaces::postBuild()
mCloseBtn = getChild<LLButton>("close_btn");
mCloseBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onBackButtonClicked, this));
- mOverflowBtn = getChild<LLButton>("overflow_btn");
- mOverflowBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onOverflowButtonClicked, this));
+ mOverflowBtn = getChild<LLMenuButton>("overflow_btn");
+ mOverflowBtn->setMouseDownCallback(boost::bind(&LLPanelPlaces::onOverflowButtonClicked, this));
mPlaceInfoBtn = getChild<LLButton>("profile_btn");
mPlaceInfoBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onProfileButtonClicked, this));
@@ -783,16 +784,7 @@ void LLPanelPlaces::onOverflowButtonClicked()
return;
}
- if (!menu->toggleVisibility())
- return;
-
- if (menu->getButtonRect().isEmpty())
- {
- menu->setButtonRect(mOverflowBtn);
- }
- menu->updateParent(LLMenuGL::sMenuContainer);
- LLRect rect = mOverflowBtn->getRect();
- LLMenuGL::showPopup(this, menu, rect.mRight, rect.mTop);
+ mOverflowBtn->setMenu(menu, LLMenuButton::MP_TOP_RIGHT);
}
void LLPanelPlaces::onProfileButtonClicked()
diff --git a/indra/newview/llpanelplaces.h b/indra/newview/llpanelplaces.h
index c3b2ab806f..5523122a0f 100644
--- a/indra/newview/llpanelplaces.h
+++ b/indra/newview/llpanelplaces.h
@@ -47,6 +47,7 @@ class LLPlacesParcelObserver;
class LLRemoteParcelInfoObserver;
class LLTabContainer;
class LLToggleableMenu;
+class LLMenuButton;
typedef std::pair<LLUUID, std::string> folder_pair_t;
@@ -123,7 +124,7 @@ private:
LLButton* mSaveBtn;
LLButton* mCancelBtn;
LLButton* mCloseBtn;
- LLButton* mOverflowBtn;
+ LLMenuButton* mOverflowBtn;
LLButton* mPlaceInfoBtn;
LLPlacesInventoryObserver* mInventoryObserver;
diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp
index fff8ccb912..9b35e78134 100644
--- a/indra/newview/llpanelteleporthistory.cpp
+++ b/indra/newview/llpanelteleporthistory.cpp
@@ -181,9 +181,11 @@ void LLTeleportHistoryFlatItem::setRegionName(const std::string& name)
void LLTeleportHistoryFlatItem::updateTitle()
{
+ static LLUIColor sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", LLColor4U(255, 255, 255));
+
LLTextUtil::textboxSetHighlightedVal(
mTitle,
- LLStyle::Params(),
+ LLStyle::Params().color(sFgColor),
mRegionName,
mHighlight);
}
diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp
index d63a48647d..0dff087553 100644
--- a/indra/newview/llremoteparcelrequest.cpp
+++ b/indra/newview/llremoteparcelrequest.cpp
@@ -77,23 +77,20 @@ void LLRemoteParcelRequestResponder::error(U32 status, const std::string& reason
void LLRemoteParcelInfoProcessor::addObserver(const LLUUID& parcel_id, LLRemoteParcelInfoObserver* observer)
{
- // Check if the observer is already in observers list for this UUID
observer_multimap_t::iterator it;
+ observer_multimap_t::iterator start = mObservers.lower_bound(parcel_id);
+ observer_multimap_t::iterator end = mObservers.upper_bound(parcel_id);
- it = mObservers.find(parcel_id);
- while (it != mObservers.end())
+ // Check if the observer is already in observers list for this UUID
+ for(it = start; it != end; ++it)
{
- if (it->second == observer)
+ if (it->second.get() == observer)
{
return;
}
- else
- {
- ++it;
- }
}
- mObservers.insert(std::pair<LLUUID, LLRemoteParcelInfoObserver*>(parcel_id, observer));
+ mObservers.insert(std::make_pair(parcel_id, observer->getObserverHandle()));
}
void LLRemoteParcelInfoProcessor::removeObserver(const LLUUID& parcel_id, LLRemoteParcelInfoObserver* observer)
@@ -104,19 +101,16 @@ void LLRemoteParcelInfoProcessor::removeObserver(const LLUUID& parcel_id, LLRemo
}
observer_multimap_t::iterator it;
+ observer_multimap_t::iterator start = mObservers.lower_bound(parcel_id);
+ observer_multimap_t::iterator end = mObservers.upper_bound(parcel_id);
- it = mObservers.find(parcel_id);
- while (it != mObservers.end())
+ for(it = start; it != end; ++it)
{
- if (it->second == observer)
+ if (it->second.get() == observer)
{
mObservers.erase(it);
break;
}
- else
- {
- ++it;
- }
}
}
@@ -141,13 +135,35 @@ void LLRemoteParcelInfoProcessor::processParcelInfoReply(LLMessageSystem* msg, v
msg->getS32 ("Data", "SalePrice", parcel_data.sale_price);
msg->getS32 ("Data", "AuctionID", parcel_data.auction_id);
- LLRemoteParcelInfoProcessor::observer_multimap_t observers = LLRemoteParcelInfoProcessor::getInstance()->mObservers;
+ LLRemoteParcelInfoProcessor::observer_multimap_t & observers = LLRemoteParcelInfoProcessor::getInstance()->mObservers;
+
+ typedef std::vector<observer_multimap_t::iterator> deadlist_t;
+ deadlist_t dead_iters;
- observer_multimap_t::iterator oi = observers.find(parcel_data.parcel_id);
+ observer_multimap_t::iterator oi;
+ observer_multimap_t::iterator start = observers.lower_bound(parcel_data.parcel_id);
observer_multimap_t::iterator end = observers.upper_bound(parcel_data.parcel_id);
- for (; oi != end; ++oi)
+
+ for (oi = start; oi != end; ++oi)
+ {
+ LLRemoteParcelInfoObserver * observer = oi->second.get();
+ if(observer)
+ {
+ observer->processParcelInfo(parcel_data);
+ }
+ else
+ {
+ // the handle points to an expired observer, so don't keep it
+ // around anymore
+ dead_iters.push_back(oi);
+ }
+ }
+
+ deadlist_t::iterator i;
+ deadlist_t::iterator end_dead = dead_iters.end();
+ for(i = dead_iters.begin(); i != end_dead; ++i)
{
- oi->second->processParcelInfo(parcel_data);
+ observers.erase(*i);
}
}
diff --git a/indra/newview/llremoteparcelrequest.h b/indra/newview/llremoteparcelrequest.h
index a6c62995a9..74cf1616df 100644
--- a/indra/newview/llremoteparcelrequest.h
+++ b/indra/newview/llremoteparcelrequest.h
@@ -98,7 +98,7 @@ public:
static void processParcelInfoReply(LLMessageSystem* msg, void**);
private:
- typedef std::multimap<LLUUID, LLRemoteParcelInfoObserver*> observer_multimap_t;
+ typedef std::multimap<LLUUID, LLHandle<LLRemoteParcelInfoObserver> > observer_multimap_t;
observer_multimap_t mObservers;
};
diff --git a/indra/newview/llscriptfloater.cpp b/indra/newview/llscriptfloater.cpp
index 2334f0cde5..170e23e4c5 100644
--- a/indra/newview/llscriptfloater.cpp
+++ b/indra/newview/llscriptfloater.cpp
@@ -32,11 +32,13 @@
#include "llchannelmanager.h"
#include "llchiclet.h"
#include "llfloaterreg.h"
+#include "lllslconstants.h"
#include "llnotifications.h"
#include "llnotificationsutil.h"
#include "llscreenchannel.h"
#include "llsyswellwindow.h"
#include "lltoastnotifypanel.h"
+#include "lltoastscripttextbox.h"
#include "lltrans.h"
#include "llviewerwindow.h"
#include "llimfloater.h"
@@ -151,10 +153,18 @@ void LLScriptFloater::createForm(const LLUUID& notification_id)
// create new form
LLRect toast_rect = getRect();
- // LLToastNotifyPanel will fit own content in vertical direction,
- // but it needs an initial rect to properly calculate its width
- // Use an initial rect of the script floater to make the floater window more configurable.
- mScriptForm = new LLToastNotifyPanel(notification, toast_rect);
+ if (isScriptTextbox(notification))
+ {
+ mScriptForm = new LLToastScriptTextbox(notification);
+ }
+ else
+ {
+ // LLToastNotifyPanel will fit own content in vertical direction,
+ // but it needs an initial rect to properly calculate its width
+ // Use an initial rect of the script floater to make the floater
+ // window more configurable.
+ mScriptForm = new LLToastNotifyPanel(notification, toast_rect);
+ }
addChild(mScriptForm);
// position form on floater
@@ -564,4 +574,32 @@ void LLScriptFloaterManager::setFloaterVisible(const LLUUID& notification_id, bo
}
}
+//////////////////////////////////////////////////////////////////
+
+bool LLScriptFloater::isScriptTextbox(LLNotificationPtr notification)
+{
+ // get a form for the notification
+ LLNotificationFormPtr form(notification->getForm());
+
+ if (form)
+ {
+ // get number of elements in the form
+ int num_options = form->getNumElements();
+
+ // if ANY of the buttons have the magic lltextbox string as
+ // name, then treat the whole dialog as a simple text entry
+ // box (i.e. mixed button and textbox forms are not supported)
+ for (int i=0; i<num_options; ++i)
+ {
+ LLSD form_element = form->getElement(i);
+ if (form_element["name"].asString() == TEXTBOX_MAGIC_TOKEN)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
// EOF
diff --git a/indra/newview/llscriptfloater.h b/indra/newview/llscriptfloater.h
index da70bb4334..dc52baa115 100644
--- a/indra/newview/llscriptfloater.h
+++ b/indra/newview/llscriptfloater.h
@@ -28,6 +28,7 @@
#define LL_SCRIPTFLOATER_H
#include "lltransientdockablefloater.h"
+#include "llnotificationptr.h"
class LLToastNotifyPanel;
@@ -203,6 +204,8 @@ protected:
void dockToChiclet(bool dock);
private:
+ bool isScriptTextbox(LLNotificationPtr notification);
+
LLToastNotifyPanel* mScriptForm;
LLUUID mNotificationId;
LLUUID mObjectId;
diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp
index 1999f14828..b316171604 100644
--- a/indra/newview/llsidepanelappearance.cpp
+++ b/indra/newview/llsidepanelappearance.cpp
@@ -183,12 +183,15 @@ void LLSidepanelAppearance::onOpen(const LLSD& key)
void LLSidepanelAppearance::onVisibilityChange(const LLSD &new_visibility)
{
- updateToVisibility(new_visibility);
+ LLSD visibility;
+ visibility["visible"] = new_visibility.asBoolean();
+ visibility["reset_accordion"] = true;
+ updateToVisibility(visibility);
}
void LLSidepanelAppearance::updateToVisibility(const LLSD &new_visibility)
{
- if (new_visibility.asBoolean())
+ if (new_visibility["visible"].asBoolean())
{
bool is_outfit_edit_visible = mOutfitEdit && mOutfitEdit->getVisible();
bool is_wearable_edit_visible = mEditWearable && mEditWearable->getVisible();
@@ -209,7 +212,7 @@ void LLSidepanelAppearance::updateToVisibility(const LLSD &new_visibility)
}
}
- if (is_outfit_edit_visible)
+ if (is_outfit_edit_visible && new_visibility["reset_accordion"].asBoolean())
{
mOutfitEdit->resetAccordionState();
}
diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp
index 81b2fc0ae0..9c8557c017 100644
--- a/indra/newview/llsidetray.cpp
+++ b/indra/newview/llsidetray.cpp
@@ -118,7 +118,7 @@ public:
protected:
LLSideTrayTab(const Params& params);
- void dock();
+ void dock(LLFloater* floater_tab);
void undock(LLFloater* floater_tab);
LLSideTray* getSideTray();
@@ -259,7 +259,7 @@ void LLSideTrayTab::toggleTabDocked()
if (docking)
{
- dock();
+ dock(floater_tab);
}
else
{
@@ -271,11 +271,14 @@ void LLSideTrayTab::toggleTabDocked()
LLFloaterReg::toggleInstance("side_bar_tab", tab_name);
}
-void LLSideTrayTab::dock()
+void LLSideTrayTab::dock(LLFloater* floater_tab)
{
LLSideTray* side_tray = getSideTray();
if (!side_tray) return;
+ // Before docking the tab, reset its (and its children's) transparency to default (STORM-688).
+ floater_tab->updateTransparency(TT_DEFAULT);
+
if (!side_tray->addTab(this))
{
llwarns << "Failed to add tab " << getName() << " to side tray" << llendl;
@@ -298,7 +301,11 @@ static void on_minimize(LLSidepanelAppearance* panel, LLSD minimized)
{
if (!panel) return;
bool visible = !minimized.asBoolean();
- panel->updateToVisibility(LLSD(visible));
+ LLSD visibility;
+ visibility["visible"] = visible;
+ // Do not reset accordion state on minimize (STORM-375)
+ visibility["reset_accordion"] = false;
+ panel->updateToVisibility(visibility);
}
void LLSideTrayTab::undock(LLFloater* floater_tab)
@@ -1028,7 +1035,8 @@ void LLSideTray::arrange()
}
// The tab buttons should be shown only if there is at least one non-detached tab.
- mButtonsPanel->setVisible(hasTabs());
+ // Also hide them in mouse-look mode.
+ mButtonsPanel->setVisible(hasTabs() && !gAgentCamera.cameraMouselook());
}
// Detach those tabs that were detached when the viewer exited last time.
diff --git a/indra/newview/llsidetray.h b/indra/newview/llsidetray.h
index 4c23a1920b..3c572dde95 100644
--- a/indra/newview/llsidetray.h
+++ b/indra/newview/llsidetray.h
@@ -40,6 +40,8 @@ class LLSideTray : public LLPanel, private LLDestroyClass<LLSideTray>
{
friend class LLUICtrlFactory;
friend class LLDestroyClass<LLSideTray>;
+ friend class LLSideTrayTab;
+ friend class LLSideTrayButton;
public:
LOG_CLASS(LLSideTray);
@@ -126,11 +128,6 @@ public:
}
/*
- * get currently active tab
- */
- const LLSideTrayTab* getActiveTab() const { return mActiveTab; }
-
- /*
* collapse SideBar, hiding visible tab and moving tab buttons
* to the right corner of the screen
*/
@@ -163,32 +160,28 @@ public:
virtual BOOL postBuild();
- void onTabButtonClick(std::string name);
- void onToggleCollapse();
-
- bool addChild (LLView* view, S32 tab_group);
- bool removeTab (LLSideTrayTab* tab); // Used to detach tabs temporarily
- bool addTab (LLSideTrayTab* tab); // Used to re-attach tabs
-
BOOL handleMouseDown (S32 x, S32 y, MASK mask);
void reshape (S32 width, S32 height, BOOL called_from_parent = TRUE);
- void processTriState ();
-
+
void updateSidetrayVisibility();
commit_signal_t& getCollapseSignal() { return mCollapseSignal; }
void handleLoginComplete();
- LLSideTrayTab* getTab (const std::string& name);
-
bool isTabAttached (const std::string& name);
protected:
+ bool addChild (LLView* view, S32 tab_group);
+ bool removeTab (LLSideTrayTab* tab); // Used to detach tabs temporarily
+ bool addTab (LLSideTrayTab* tab); // Used to re-attach tabs
bool hasTabs ();
+ const LLSideTrayTab* getActiveTab() const { return mActiveTab; }
+ LLSideTrayTab* getTab(const std::string& name);
+
void createButtons ();
LLButton* createButton (const std::string& name,const std::string& image,const std::string& tooltip,
@@ -196,11 +189,15 @@ protected:
void arrange ();
void detachTabs ();
void reflectCollapseChange();
+ void processTriState ();
void toggleTabButton (LLSideTrayTab* tab);
LLPanel* openChildPanel (LLSideTrayTab* tab, const std::string& panel_name, const LLSD& params);
+ void onTabButtonClick(std::string name);
+ void onToggleCollapse();
+
private:
// Implementation of LLDestroyClass<LLSideTray>
static void destroyClass()
diff --git a/indra/newview/llspeakbutton.cpp b/indra/newview/llspeakbutton.cpp
index 3dce66f394..c76ecae4a2 100644
--- a/indra/newview/llspeakbutton.cpp
+++ b/indra/newview/llspeakbutton.cpp
@@ -134,8 +134,11 @@ LLSpeakButton::LLSpeakButton(const Params& p)
LLSpeakButton::~LLSpeakButton()
{
- LLTransientFloaterMgr::getInstance()->removeControlView(mSpeakBtn);
- LLTransientFloaterMgr::getInstance()->removeControlView(mShowBtn);
+ if(LLTransientFloaterMgr::instanceExists())
+ {
+ LLTransientFloaterMgr::getInstance()->removeControlView(mSpeakBtn);
+ LLTransientFloaterMgr::getInstance()->removeControlView(mShowBtn);
+ }
}
void LLSpeakButton::setSpeakToolTip(const std::string& msg)
diff --git a/indra/newview/llspeakingindicatormanager.cpp b/indra/newview/llspeakingindicatormanager.cpp
index ede1d6bebe..9b38bf22ff 100644
--- a/indra/newview/llspeakingindicatormanager.cpp
+++ b/indra/newview/llspeakingindicatormanager.cpp
@@ -308,7 +308,10 @@ void LLSpeakingIndicatorManager::registerSpeakingIndicator(const LLUUID& speaker
void LLSpeakingIndicatorManager::unregisterSpeakingIndicator(const LLUUID& speaker_id, const LLSpeakingIndicator* const speaking_indicator)
{
- SpeakingIndicatorManager::instance().unregisterSpeakingIndicator(speaker_id, speaking_indicator);
+ if(SpeakingIndicatorManager::instanceExists())
+ {
+ SpeakingIndicatorManager::instance().unregisterSpeakingIndicator(speaker_id, speaking_indicator);
+ }
}
// EOF
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 5ee4599200..80cf7e3cd0 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -198,6 +198,7 @@
// exported globals
//
bool gAgentMovementCompleted = false;
+S32 gMaxAgentGroups;
std::string SCREEN_HOME_FILENAME = "screen_home.bmp";
std::string SCREEN_LAST_FILENAME = "screen_last.bmp";
@@ -3151,6 +3152,18 @@ bool process_login_success_response()
LLViewerMedia::openIDSetup(openid_url, openid_token);
}
+ if(response.has("max-agent-groups")) {
+ std::string max_agent_groups(response["max-agent-groups"]);
+ gMaxAgentGroups = atoi(max_agent_groups.c_str());
+ LL_INFOS("LLStartup") << "gMaxAgentGroups read from login.cgi: "
+ << gMaxAgentGroups << LL_ENDL;
+ }
+ else {
+ gMaxAgentGroups = DEFAULT_MAX_AGENT_GROUPS;
+ LL_INFOS("LLStartup") << "using gMaxAgentGroups default: "
+ << gMaxAgentGroups << LL_ENDL;
+ }
+
bool success = false;
// JC: gesture loading done below, when we have an asset system
// in place. Don't delete/clear gUserCredentials until then.
diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h
index be1043cf91..b3d9ef1dcc 100644
--- a/indra/newview/llstartup.h
+++ b/indra/newview/llstartup.h
@@ -70,6 +70,7 @@ typedef enum {
// exported symbols
extern bool gAgentMovementCompleted;
+extern S32 gMaxAgentGroups;
extern LLPointer<LLViewerTexture> gStartTexture;
class LLStartUp
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 328298bda4..56e9739350 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -564,25 +564,27 @@ void LLFloaterTexturePicker::draw()
LLRect interior = border;
interior.stretch( -1 );
+ // If the floater is focused, don't apply its alpha to the texture (STORM-677).
+ const F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
if( mTexturep )
{
if( mTexturep->getComponents() == 4 )
{
- gl_rect_2d_checkerboard( interior );
+ gl_rect_2d_checkerboard( interior, alpha );
}
- gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep );
+ gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep, UI_VERTEX_COLOR % alpha );
// Pump the priority
mTexturep->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) );
}
else if (!mFallbackImage.isNull())
{
- mFallbackImage->draw(interior);
+ mFallbackImage->draw(interior, UI_VERTEX_COLOR % alpha);
}
else
{
- gl_rect_2d( interior, LLColor4::grey, TRUE );
+ gl_rect_2d( interior, LLColor4::grey % alpha, TRUE );
// Draw X
gl_draw_x(interior, LLColor4::black );
@@ -1263,23 +1265,25 @@ void LLTextureCtrl::draw()
LLRect interior = border;
interior.stretch( -1 );
+ // If we're in a focused floater, don't apply the floater's alpha to the texture (STORM-677).
+ const F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
if( mTexturep )
{
if( mTexturep->getComponents() == 4 )
{
- gl_rect_2d_checkerboard( interior );
+ gl_rect_2d_checkerboard( interior, alpha );
}
- gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep);
+ gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep, UI_VERTEX_COLOR % alpha);
mTexturep->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) );
}
else if (!mFallbackImage.isNull())
{
- mFallbackImage->draw(interior);
+ mFallbackImage->draw(interior, UI_VERTEX_COLOR % alpha);
}
else
{
- gl_rect_2d( interior, LLColor4::grey, TRUE );
+ gl_rect_2d( interior, LLColor4::grey % alpha, TRUE );
// Draw X
gl_draw_x( interior, LLColor4::black );
diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp
index 371aad64bb..563c27c4d7 100644
--- a/indra/newview/lltoastgroupnotifypanel.cpp
+++ b/indra/newview/lltoastgroupnotifypanel.cpp
@@ -60,7 +60,7 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification
LLGroupData groupData;
if (!gAgent.getGroupData(payload["group_id"].asUUID(),groupData))
{
- llwarns << "Group notice for unkown group: " << payload["group_id"].asUUID() << llendl;
+ llwarns << "Group notice for unknown group: " << payload["group_id"].asUUID() << llendl;
}
//group icon
diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp
index 9017f5ec55..3f7dc24ade 100644
--- a/indra/newview/lltoastnotifypanel.cpp
+++ b/indra/newview/lltoastnotifypanel.cpp
@@ -33,6 +33,7 @@
// library includes
#include "lldbstrings.h"
+#include "lllslconstants.h"
#include "llnotifications.h"
#include "lluiconstants.h"
#include "llrect.h"
@@ -70,11 +71,11 @@ mCloseNotificationOnDestroy(true)
mControlPanel = getChild<LLPanel>("control_panel");
BUTTON_WIDTH = gSavedSettings.getS32("ToastButtonWidth");
// customize panel's attributes
- // is it intended for displaying a tip
+ // is it intended for displaying a tip?
mIsTip = notification->getType() == "notifytip";
- // is it a script dialog
+ // is it a script dialog?
mIsScriptDialog = (notification->getName() == "ScriptDialog" || notification->getName() == "ScriptDialogGroup");
- // is it a caution
+ // is it a caution?
//
// caution flag can be set explicitly by specifying it in the notification payload, or it can be set implicitly if the
// notify xml template specifies that it is a caution
@@ -139,6 +140,12 @@ mCloseNotificationOnDestroy(true)
LLSD form_element = form->getElement(i);
if (form_element["type"].asString() != "button")
{
+ // not a button.
+ continue;
+ }
+ if (form_element["name"].asString() == TEXTBOX_MAGIC_TOKEN)
+ {
+ // a textbox pretending to be a button.
continue;
}
LLButton* new_button = createButton(form_element, TRUE);
@@ -159,7 +166,7 @@ mCloseNotificationOnDestroy(true)
if(h_pad < 2*HPAD)
{
/*
- * Probably it is a scriptdialog toast
+ * Probably it is a scriptdialog toast
* for a scriptdialog toast h_pad can be < 2*HPAD if we have a lot of buttons.
* In last case set default h_pad to avoid heaping of buttons
*/
@@ -261,7 +268,7 @@ LLButton* LLToastNotifyPanel::createButton(const LLSD& form_element, BOOL is_opt
}
else if (mIsScriptDialog && is_ignore_btn)
{
- // this is ignore button,make it smaller
+ // this is ignore button, make it smaller
p.rect.height = BTN_HEIGHT_SMALL;
p.rect.width = 1;
p.auto_resize = true;
diff --git a/indra/newview/lltoastscripttextbox.cpp b/indra/newview/lltoastscripttextbox.cpp
new file mode 100644
index 0000000000..c013f521cc
--- /dev/null
+++ b/indra/newview/lltoastscripttextbox.cpp
@@ -0,0 +1,109 @@
+/**
+ * @file lltoastscripttextbox.cpp
+ * @brief Panel for script llTextBox dialogs
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lltoastscripttextbox.h"
+
+#include "llfocusmgr.h"
+
+#include "llbutton.h"
+#include "llnotifications.h"
+#include "llviewertexteditor.h"
+
+#include "llavatarnamecache.h"
+#include "lluiconstants.h"
+#include "llui.h"
+#include "llviewercontrol.h"
+#include "lltrans.h"
+#include "llstyle.h"
+
+#include "llglheaders.h"
+#include "llagent.h"
+
+const S32 LLToastScriptTextbox::DEFAULT_MESSAGE_MAX_LINE_COUNT= 7;
+
+LLToastScriptTextbox::LLToastScriptTextbox(LLNotificationPtr& notification)
+: LLToastNotifyPanel(notification)
+{
+ buildFromFile( "panel_notify_textbox.xml");
+
+ const LLSD& payload = notification->getPayload();
+
+ //message body
+ const std::string& message = payload["message"].asString();
+
+ LLViewerTextEditor* pMessageText = getChild<LLViewerTextEditor>("message");
+ pMessageText->clear();
+
+ LLStyle::Params style;
+ style.font = pMessageText->getDefaultFont();
+ pMessageText->appendText(message, TRUE, style);
+
+ //submit button
+ LLButton* pSubmitBtn = getChild<LLButton>("btn_submit");
+ pSubmitBtn->setClickedCallback((boost::bind(&LLToastScriptTextbox::onClickSubmit, this)));
+ setDefaultBtn(pSubmitBtn);
+
+ S32 maxLinesCount;
+ std::istringstream ss( getString("message_max_lines_count") );
+ if (!(ss >> maxLinesCount))
+ {
+ maxLinesCount = DEFAULT_MESSAGE_MAX_LINE_COUNT;
+ }
+ //snapToMessageHeight(pMessageText, maxLinesCount);
+}
+
+// virtual
+LLToastScriptTextbox::~LLToastScriptTextbox()
+{
+}
+
+void LLToastScriptTextbox::close()
+{
+ die();
+}
+
+#include "lllslconstants.h"
+void LLToastScriptTextbox::onClickSubmit()
+{
+ LLViewerTextEditor* pMessageText = getChild<LLViewerTextEditor>("message");
+
+ if (pMessageText)
+ {
+ LLSD response = mNotification->getResponseTemplate();
+ response[TEXTBOX_MAGIC_TOKEN] = pMessageText->getText();
+ if (response[TEXTBOX_MAGIC_TOKEN].asString().empty())
+ {
+ // so we can distinguish between a successfully
+ // submitted blank textbox, and an ignored toast
+ response[TEXTBOX_MAGIC_TOKEN] = true;
+ }
+ mNotification->respond(response);
+ close();
+ llwarns << response << llendl;
+ }
+}
diff --git a/indra/newview/lltoastscripttextbox.h b/indra/newview/lltoastscripttextbox.h
new file mode 100644
index 0000000000..ae3b545e0a
--- /dev/null
+++ b/indra/newview/lltoastscripttextbox.h
@@ -0,0 +1,58 @@
+/**
+ * @file lltoastscripttextbox.h
+ * @brief Panel for script llTextBox dialogs
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLTOASTSCRIPTTEXTBOX_H
+#define LL_LLTOASTSCRIPTTEXTBOX_H
+
+#include "lltoastnotifypanel.h"
+#include "llnotificationptr.h"
+
+class LLButton;
+
+/**
+ * Toast panel for scripted llTextbox notifications.
+ */
+class LLToastScriptTextbox
+: public LLToastNotifyPanel
+{
+public:
+ void close();
+
+ static bool onNewNotification(const LLSD& notification);
+
+ // Non-transient messages. You can specify non-default button
+ // layouts (like one for script dialogs) by passing various
+ // numbers in for "layout".
+ LLToastScriptTextbox(LLNotificationPtr& notification);
+
+ /*virtual*/ ~LLToastScriptTextbox();
+protected:
+ void onClickSubmit();
+private:
+ static const S32 DEFAULT_MESSAGE_MAX_LINE_COUNT;
+};
+
+#endif
diff --git a/indra/newview/lltransientfloatermgr.cpp b/indra/newview/lltransientfloatermgr.cpp
index 78dd602f39..6deab96b45 100644
--- a/indra/newview/lltransientfloatermgr.cpp
+++ b/indra/newview/lltransientfloatermgr.cpp
@@ -36,8 +36,11 @@
LLTransientFloaterMgr::LLTransientFloaterMgr()
{
- gViewerWindow->getRootView()->addMouseDownCallback(boost::bind(
+ if(gViewerWindow)
+ {
+ gViewerWindow->getRootView()->addMouseDownCallback(boost::bind(
&LLTransientFloaterMgr::leftMouseClickCallback, this, _1, _2, _3));
+ }
mGroupControls.insert(std::pair<ETransientGroup, std::set<LLView*> >(GLOBAL, std::set<LLView*>()));
mGroupControls.insert(std::pair<ETransientGroup, std::set<LLView*> >(DOCKED, std::set<LLView*>()));
diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp
index 050e34ade9..8ccfdb071b 100644
--- a/indra/newview/lltranslate.cpp
+++ b/indra/newview/lltranslate.cpp
@@ -36,7 +36,7 @@
#include "llbufferstream.h"
#include "llui.h"
-#include "llversionviewer.h"
+#include "llversioninfo.h"
#include "llviewercontrol.h"
#include "jsoncpp/reader.h"
@@ -64,11 +64,11 @@ void LLTranslate::translateMessage(LLHTTPClient::ResponderPtr &result, const std
getTranslateUrl(url, from_lang, to_lang, mesg);
std::string user_agent = llformat("%s %d.%d.%d (%d)",
- LL_CHANNEL,
- LL_VERSION_MAJOR,
- LL_VERSION_MINOR,
- LL_VERSION_PATCH,
- LL_VERSION_BUILD );
+ LLVersionInfo::getChannel().c_str(),
+ LLVersionInfo::getMajor(),
+ LLVersionInfo::getMinor(),
+ LLVersionInfo::getPatch(),
+ LLVersionInfo::getBuild());
if (!m_Header.size())
{
diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp
index 733d05834a..673d0c24cf 100644
--- a/indra/newview/llversioninfo.cpp
+++ b/indra/newview/llversioninfo.cpp
@@ -95,9 +95,42 @@ const std::string &LLVersionInfo::getShortVersion()
return version;
}
+namespace
+{
+ /// Storage of the channel name the viewer is using.
+ // The channel name is set by hardcoded constant,
+ // or by calling LLVersionInfo::resetChannel()
+ std::string sWorkingChannelName(LL_CHANNEL);
+
+ // Storage for the "version and channel" string.
+ // This will get reset too.
+ std::string sVersionChannel("");
+}
+
+//static
+const std::string &LLVersionInfo::getChannelAndVersion()
+{
+ if (sVersionChannel.empty())
+ {
+ // cache the version string
+ std::ostringstream stream;
+ stream << LLVersionInfo::getChannel()
+ << " "
+ << LLVersionInfo::getVersion();
+ sVersionChannel = stream.str();
+ }
+
+ return sVersionChannel;
+}
+
//static
const std::string &LLVersionInfo::getChannel()
{
- static std::string name(LL_CHANNEL);
- return name;
+ return sWorkingChannelName;
+}
+
+void LLVersionInfo::resetChannel(const std::string& channel)
+{
+ sWorkingChannelName = channel;
+ sVersionChannel.clear(); // Reset version and channel string til next use.
}
diff --git a/indra/newview/llversioninfo.h b/indra/newview/llversioninfo.h
index e468b6ae4e..6f64544f3b 100644
--- a/indra/newview/llversioninfo.h
+++ b/indra/newview/llversioninfo.h
@@ -58,8 +58,15 @@ public:
/// return the viewer version as a string like "2.0.0"
static const std::string &getShortVersion();
+ /// return the viewer version and channel as a string
+ /// like "Second Life Release 2.0.0.200030"
+ static const std::string &getChannelAndVersion();
+
/// return the channel name, e.g. "Second Life"
static const std::string &getChannel();
+
+ /// reset the channel name used by the viewer.
+ static void resetChannel(const std::string& channel);
};
#endif
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 117e49d67f..622d09c600 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -70,6 +70,7 @@
#include "llpaneloutfitsinventory.h"
#include "llpanellogin.h"
#include "llpaneltopinfobar.h"
+#include "llupdaterservice.h"
#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
BOOL gHackGodmode = FALSE;
@@ -82,7 +83,6 @@ LLControlGroup gCrashSettings("CrashSettings"); // saved at end of session
LLControlGroup gWarningSettings("Warnings"); // persists ignored dialogs/warnings
std::string gLastRunVersion;
-std::string gCurrentVersion;
extern BOOL gResizeScreenTexture;
extern BOOL gDebugGL;
@@ -502,6 +502,18 @@ bool toggle_show_object_render_cost(const LLSD& newvalue)
return true;
}
+void toggle_updater_service_active(LLControlVariable* control, const LLSD& new_value)
+{
+ if(new_value.asBoolean())
+ {
+ LLUpdaterService().startChecking();
+ }
+ else
+ {
+ LLUpdaterService().stopChecking();
+ }
+}
+
////////////////////////////////////////////////////////////////////////////
void settings_setup_listeners()
@@ -649,6 +661,7 @@ void settings_setup_listeners()
gSavedSettings.getControl("ShowNavbarFavoritesPanel")->getSignal()->connect(boost::bind(&toggle_show_favorites_panel, _2));
gSavedSettings.getControl("ShowMiniLocationPanel")->getSignal()->connect(boost::bind(&toggle_show_mini_location_panel, _2));
gSavedSettings.getControl("ShowObjectRenderingCost")->getSignal()->connect(boost::bind(&toggle_show_object_render_cost, _2));
+ gSavedSettings.getControl("UpdaterServiceActive")->getSignal()->connect(&toggle_updater_service_active);
gSavedSettings.getControl("ForceShowGrid")->getSignal()->connect(boost::bind(&handleForceShowGrid, _2));
gSavedSettings.getControl("RenderTransparentWater")->getSignal()->connect(boost::bind(&handleRenderTransparentWaterChanged, _2));
}
diff --git a/indra/newview/llviewercontrol.h b/indra/newview/llviewercontrol.h
index 22b48f8906..d7191f5c8d 100644
--- a/indra/newview/llviewercontrol.h
+++ b/indra/newview/llviewercontrol.h
@@ -57,7 +57,5 @@ extern LLControlGroup gCrashSettings;
// Set after settings loaded
extern std::string gLastRunVersion;
-extern std::string gCurrentVersion;
-
#endif // LL_LLVIEWERCONTROL_H
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 31cf0acdd7..fae4eb3c05 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -492,7 +492,7 @@ std::string LLViewerMedia::getCurrentUserAgent()
// Just in case we need to check browser differences in A/B test
// builds.
- std::string channel = gSavedSettings.getString("VersionChannelName");
+ std::string channel = LLVersionInfo::getChannel();
// append our magic version number string to the browser user agent id
// See the HTTP 1.0 and 1.1 specifications for allowed formats:
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 54fe34e738..03490034d8 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -7795,6 +7795,9 @@ void initialize_menus()
view_listener_t::addMenu(new LLViewCheckRenderType(), "View.CheckRenderType");
view_listener_t::addMenu(new LLViewCheckHUDAttachments(), "View.CheckHUDAttachments");
+ // Me > Movement
+ view_listener_t::addMenu(new LLAdvancedAgentFlyingInfo(), "Agent.getFlying");
+
// World menu
commit.add("World.Chat", boost::bind(&handle_chat, (void*)NULL));
view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun");
@@ -7868,9 +7871,6 @@ void initialize_menus()
// Advanced Other Settings
view_listener_t::addMenu(new LLAdvancedClearGroupCache(), "Advanced.ClearGroupCache");
-
- // Advanced > Shortcuts
- view_listener_t::addMenu(new LLAdvancedAgentFlyingInfo(), "Agent.getFlying");
// Advanced > Render > Types
view_listener_t::addMenu(new LLAdvancedToggleRenderType(), "Advanced.ToggleRenderType");
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index 237aa39e6e..048691696b 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -404,8 +404,6 @@ class LLFileTakeSnapshotToDisk : public view_listener_t
gSavedSettings.getBOOL("RenderUIInSnapshot"),
FALSE))
{
- gViewerWindow->playSnapshotAnimAndSound();
-
LLPointer<LLImageFormatted> formatted;
switch(LLFloaterSnapshot::ESnapshotFormat(gSavedSettings.getS32("SnapshotFormat")))
{
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 1f54940b25..5cbd5ffa0b 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -39,6 +39,7 @@
#include "llfloaterreg.h"
#include "llfollowcamparams.h"
#include "llinventorydefines.h"
+#include "lllslconstants.h"
#include "llregionhandle.h"
#include "llsdserialize.h"
#include "llteleportflags.h"
@@ -638,7 +639,7 @@ bool join_group_response(const LLSD& notification, const LLSD& response)
if(option == 0 && !group_id.isNull())
{
// check for promotion or demotion.
- S32 max_groups = MAX_AGENT_GROUPS;
+ S32 max_groups = gMaxAgentGroups;
if(gAgent.isInGroup(group_id)) ++max_groups;
if(gAgent.mGroups.count() < max_groups)
@@ -6436,8 +6437,22 @@ const char* SCRIPT_DIALOG_HEADER = "Script Dialog:\n";
bool callback_script_dialog(const LLSD& notification, const LLSD& response)
{
LLNotificationForm form(notification["form"]);
- std::string button = LLNotification::getSelectedOptionName(response);
- S32 button_idx = LLNotification::getSelectedOption(notification, response);
+
+ std::string rtn_text;
+ S32 button_idx;
+ button_idx = LLNotification::getSelectedOption(notification, response);
+ if (response[TEXTBOX_MAGIC_TOKEN].isDefined())
+ {
+ if (response[TEXTBOX_MAGIC_TOKEN].isString())
+ rtn_text = response[TEXTBOX_MAGIC_TOKEN].asString();
+ else
+ rtn_text.clear(); // bool marks empty string
+ }
+ else
+ {
+ rtn_text = LLNotification::getSelectedOptionName(response);
+ }
+
// Didn't click "Ignore"
if (button_idx != -1)
{
@@ -6450,7 +6465,7 @@ bool callback_script_dialog(const LLSD& notification, const LLSD& response)
msg->addUUID("ObjectID", notification["payload"]["object_id"].asUUID());
msg->addS32("ChatChannel", notification["payload"]["chat_channel"].asInteger());
msg->addS32("ButtonIndex", button_idx);
- msg->addString("ButtonLabel", button);
+ msg->addString("ButtonLabel", rtn_text);
msg->sendReliable(LLHost(notification["payload"]["sender"].asString()));
}
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 46c78e2bb4..546ee9a334 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -48,6 +48,7 @@
#include "llagent.h"
#include "llagentcamera.h"
#include "llviewercontrol.h"
+#include "llversioninfo.h"
#include "llfloatertools.h"
#include "lldebugview.h"
#include "llfasttimerview.h"
@@ -749,7 +750,7 @@ void send_stats()
// send fps only for time app spends in foreground
agent["fps"] = (F32)gForegroundFrameCount / gForegroundTime.getElapsedTimeF32();
- agent["version"] = gCurrentVersion;
+ agent["version"] = LLVersionInfo::getChannelAndVersion();
std::string language = LLUI::getLanguage();
agent["language"] = language;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 743def4a0c..a7790243ed 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2266,6 +2266,20 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
return TRUE;
}
+ // If "Pressing letter keys starts local chat" option is selected, we are not in mouselook,
+ // no view has keyboard focus, this is a printable character key (and no modifier key is
+ // pressed except shift), then give focus to nearby chat (STORM-560)
+ if ( gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() &&
+ !keyboard_focus && key < 0x80 && (mask == MASK_NONE || mask == MASK_SHIFT) )
+ {
+ LLLineEditor* chat_editor = LLBottomTray::instanceExists() ? LLBottomTray::getInstance()->getNearbyChatBar()->getChatBox() : NULL;
+ if (chat_editor)
+ {
+ // passing NULL here, character will be added later when it is handled by character handler.
+ LLBottomTray::getInstance()->getNearbyChatBar()->startChat(NULL);
+ return TRUE;
+ }
+ }
// give menus a chance to handle unmodified accelerator keys
if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask))
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 7ae1f672e8..f4dec9294f 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -3024,7 +3024,7 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name)
std::deque<LLChat>::iterator chat_iter = mChats.begin();
mNameText->clearString();
- LLColor4 new_chat = LLUIColorTable::instance().getColor( "NameTagChat" );
+ LLColor4 new_chat = LLUIColorTable::instance().getColor( isSelf() ? "UserChatColor" : "AgentChatColor" );
LLColor4 normal_chat = lerp(new_chat, LLColor4(0.8f, 0.8f, 0.8f, 1.f), 0.7f);
LLColor4 old_chat = lerp(normal_chat, LLColor4(0.6f, 0.6f, 0.6f, 1.f), 0.7f);
if (mTyping && mChats.size() >= MAX_BUBBLE_CHAT_UTTERANCES)
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 0250627d1b..5f9e343907 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -783,11 +783,19 @@ void LLVOAvatarSelf::removeMissingBakedTextures()
for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
{
const S32 te = mBakedTextureDatas[i].mTextureIndex;
- LLViewerTexture* tex = getTEImage(te) ;
+ const LLViewerTexture* tex = getTEImage(te);
+
+ // Replace with default if we can't find the asset, assuming the
+ // default is actually valid (which it should be unless something
+ // is seriously wrong).
if (!tex || tex->isMissingAsset())
{
- setTEImage(te, LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR));
- removed = TRUE;
+ LLViewerTexture *imagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR);
+ if (imagep)
+ {
+ setTEImage(te, imagep);
+ removed = TRUE;
+ }
}
}
@@ -823,7 +831,6 @@ void LLVOAvatarSelf::updateRegion(LLViewerRegion *regionp)
// << llendl;
}
-
if (!regionp || (regionp->getHandle() != mLastRegionHandle))
{
if (mLastRegionHandle != 0)
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index aeea2306f7..62441fd984 100644
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -139,9 +139,6 @@
name="AvatarListItemIconVoiceLeftColor"
reference="AvatarListItemIconOfflineColor" />
<color
- name="BackgroundChatColor"
- reference="DkGray_66" />
- <color
name="ButtonBorderColor"
reference="Unused?" />
<color
diff --git a/indra/newview/skins/default/xui/da/floater_avatar_picker.xml b/indra/newview/skins/default/xui/da/floater_avatar_picker.xml
index a337da9b51..e97089f61e 100644
--- a/indra/newview/skins/default/xui/da/floater_avatar_picker.xml
+++ b/indra/newview/skins/default/xui/da/floater_avatar_picker.xml
@@ -24,6 +24,10 @@
Indtast en del af beboerens navn:
</text>
<button label="Find" label_selected="Find" name="Find"/>
+ <scroll_list name="SearchResults">
+ <columns label="Navn" name="name"/>
+ <columns label="Brugernavn" name="username"/>
+ </scroll_list>
</panel>
<panel label="Venner" name="FriendsPanel">
<text name="InstructSelectFriend">
@@ -39,6 +43,10 @@
meter
</text>
<button label="Gentegn liste" label_selected="Gentegn liste" name="Refresh"/>
+ <scroll_list name="NearMe">
+ <columns label="Navn" name="name"/>
+ <columns label="Brugernavn" name="username"/>
+ </scroll_list>
</panel>
</tab_container>
<button label="OK" label_selected="OK" name="ok_btn"/>
diff --git a/indra/newview/skins/default/xui/da/floater_bumps.xml b/indra/newview/skins/default/xui/da/floater_bumps.xml
index 1db2e93fd2..6b265832cd 100644
--- a/indra/newview/skins/default/xui/da/floater_bumps.xml
+++ b/indra/newview/skins/default/xui/da/floater_bumps.xml
@@ -4,10 +4,10 @@
Ingen registreret
</floater.string>
<floater.string name="bump">
- [TIME] [NAME] ramte dig
+ [TIME] [NAME] puffede til dig
</floater.string>
<floater.string name="llpushobject">
- [TIME] [NAME] skubbede dig med et script
+ [TIME] [NAME] skubbede til dig via et script
</floater.string>
<floater.string name="selected_object_collide">
[TIME] [NAME] ramte dig med et objekt
diff --git a/indra/newview/skins/default/xui/da/floater_buy_object.xml b/indra/newview/skins/default/xui/da/floater_buy_object.xml
index f9e18dcf65..7eb4787139 100644
--- a/indra/newview/skins/default/xui/da/floater_buy_object.xml
+++ b/indra/newview/skins/default/xui/da/floater_buy_object.xml
@@ -1,26 +1,29 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="contents" title="KØB KOPI AF OBJEKT">
+ <floater.string name="title_buy_text">
+ Køb
+ </floater.string>
+ <floater.string name="title_buy_copy_text">
+ Køb en kopi af
+ </floater.string>
+ <floater.string name="no_copy_text">
+ (kopiér ej)
+ </floater.string>
+ <floater.string name="no_modify_text">
+ (ændre ej)
+ </floater.string>
+ <floater.string name="no_transfer_text">
+ (videregiv ej)
+ </floater.string>
<text name="contents_text">
Indeholder:
</text>
<text name="buy_text">
- Køb for L$[AMOUNT] fra [NAME]?
+ Køb for L$[AMOUNT] af:
+ </text>
+ <text name="buy_name_text">
+ [NAME]?
</text>
- <button label="Annullér" label_selected="Annullér" name="cancel_btn"/>
<button label="Køb" label_selected="Køb" name="buy_btn"/>
- <string name="title_buy_text">
- Køb
- </string>
- <string name="title_buy_copy_text">
- Køb en kopi af
- </string>
- <string name="no_copy_text">
- (kopiér ej)
- </string>
- <string name="no_modify_text">
- (ændre ej)
- </string>
- <string name="no_transfer_text">
- (videregiv ej)
- </string>
+ <button label="Annullér" label_selected="Annullér" name="cancel_btn"/>
</floater>
diff --git a/indra/newview/skins/default/xui/da/floater_display_name.xml b/indra/newview/skins/default/xui/da/floater_display_name.xml
new file mode 100644
index 0000000000..e848006d8b
--- /dev/null
+++ b/indra/newview/skins/default/xui/da/floater_display_name.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="Display Name" title="ÆNDRE VISNINGSNAVN">
+ <text name="info_text">
+ Det navn du giver din avatar kaldes dit visningsnavn. Du kan ændre dette en gang om ugen.
+ </text>
+ <text name="lockout_text">
+ Du kan ikke ændre dit visningsnavn før: [TIME].
+ </text>
+ <text name="set_name_label">
+ Nyt visningsnavn:
+ </text>
+ <text name="name_confirm_label">
+ Indtast dit nye navn igen for at bekræfte:
+ </text>
+ <button label="Gem" name="save_btn" tool_tip="Gem dit nye visningsnavn"/>
+ <button label="Nulstil" name="reset_btn" tool_tip="Omdøb visningsnavn til samme som brugernavn"/>
+ <button label="Annullér" name="cancel_btn"/>
+</floater>
diff --git a/indra/newview/skins/default/xui/da/floater_event.xml b/indra/newview/skins/default/xui/da/floater_event.xml
index 58f2e555dd..a9eddaaf8d 100644
--- a/indra/newview/skins/default/xui/da/floater_event.xml
+++ b/indra/newview/skins/default/xui/da/floater_event.xml
@@ -1,40 +1,11 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<floater
- follows="all"
- height="400"
- can_resize="true"
- help_topic="event_details"
- label="Event"
- layout="topleft"
- name="Event"
- save_rect="true"
- save_visibility="false"
- title="EVENT DETAILS"
- width="600">
- <floater.string
- name="loading_text">
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater can_resize="true" follows="all" height="400" help_topic="event_details" label="Event" layout="topleft" name="Event" save_rect="true" save_visibility="false" title="EVENT DETAILS" width="600">
+ <floater.string name="loading_text">
Henter...
</floater.string>
- <floater.string
- name="done_text">
- Done
- </floater.string>
- <web_browser
- trusted_content="true"
- follows="left|right|top|bottom"
- layout="topleft"
- left="10"
- name="browser"
- height="365"
- width="580"
- top="0"/>
- <text
- follows="bottom|left"
- height="16"
- layout="topleft"
- left_delta="0"
- name="status_text"
- top_pad="10"
- width="150" />
+ <floater.string name="done_text">
+ Færdig
+ </floater.string>
+ <web_browser follows="left|right|top|bottom" height="365" layout="topleft" left="10" name="browser" top="0" trusted_content="true" width="580"/>
+ <text follows="bottom|left" height="16" layout="topleft" left_delta="0" name="status_text" top_pad="10" width="150"/>
</floater>
-
diff --git a/indra/newview/skins/default/xui/da/floater_incoming_call.xml b/indra/newview/skins/default/xui/da/floater_incoming_call.xml
index 7a3c3e466a..dd8cb6f97a 100644
--- a/indra/newview/skins/default/xui/da/floater_incoming_call.xml
+++ b/indra/newview/skins/default/xui/da/floater_incoming_call.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="incoming call" title="UKENDT PERSON KALDER OP">
+<floater name="incoming call" title="Indgående opkald">
<floater.string name="lifetime">
5
</floater.string>
diff --git a/indra/newview/skins/default/xui/da/floater_pay.xml b/indra/newview/skins/default/xui/da/floater_pay.xml
index 5ebdd3f084..96ec106803 100644
--- a/indra/newview/skins/default/xui/da/floater_pay.xml
+++ b/indra/newview/skins/default/xui/da/floater_pay.xml
@@ -11,7 +11,7 @@
</text>
<icon name="icon_person" tool_tip="Person"/>
<text name="payee_name">
- Test Name That Is Extremely Long To Check Clipping
+ Test navn der er meget lang for at checke afkortning
</text>
<button label="L$1" label_selected="L$1" name="fastpay 1"/>
<button label="L$5" label_selected="L$5" name="fastpay 5"/>
diff --git a/indra/newview/skins/default/xui/da/floater_tools.xml b/indra/newview/skins/default/xui/da/floater_tools.xml
index 6fda088b51..781adcd50b 100644
--- a/indra/newview/skins/default/xui/da/floater_tools.xml
+++ b/indra/newview/skins/default/xui/da/floater_tools.xml
@@ -168,13 +168,13 @@
Skaber:
</text>
<text name="Creator Name">
- Thrax Linden
+ Mrs. Esbee Linden (esbee.linden)
</text>
<text name="Owner:">
Ejer:
</text>
<text name="Owner Name">
- Thrax Linden
+ Mrs. Erica &quot;Moose&quot; Linden (erica.linden)
</text>
<text name="Group:">
Gruppe:
diff --git a/indra/newview/skins/default/xui/da/floater_voice_controls.xml b/indra/newview/skins/default/xui/da/floater_voice_controls.xml
index 4c956f13a7..69de696bf5 100644
--- a/indra/newview/skins/default/xui/da/floater_voice_controls.xml
+++ b/indra/newview/skins/default/xui/da/floater_voice_controls.xml
@@ -19,10 +19,10 @@
<layout_panel name="my_panel">
<text name="user_text" value="Min avatar:"/>
</layout_panel>
- <layout_panel name="leave_call_panel">
+ <layout_panel name="leave_call_panel">
<layout_stack name="voice_effect_and_leave_call_stack">
<layout_panel name="leave_call_btn_panel">
- <button label="Forlad opkald" name="leave_call_btn"/>
+ <button label="Forlad samtale" name="leave_call_btn"/>
</layout_panel>
</layout_stack>
</layout_panel>
diff --git a/indra/newview/skins/default/xui/da/inspect_avatar.xml b/indra/newview/skins/default/xui/da/inspect_avatar.xml
index d4bc0813e5..f581210e1b 100644
--- a/indra/newview/skins/default/xui/da/inspect_avatar.xml
+++ b/indra/newview/skins/default/xui/da/inspect_avatar.xml
@@ -10,6 +10,11 @@
<string name="Details">
[SL_PROFILE]
</string>
+ <text name="user_name_small" value="Grumpity ProductEngine med et langt navn"/>
+ <text name="user_slid" value="james.linden"/>
+ <text name="user_details">
+ Dette er min second life beskrivelse og jeg synes den er rigtig god. Men af en eller ande grund er min beskrivelse meget lang fordi jeg taler en hel masse
+ </text>
<slider name="volume_slider" tool_tip="Stemme lydstyrke" value="0.5"/>
<button label="Tilføj ven" name="add_friend_btn"/>
<button label="IM" name="im_btn"/>
diff --git a/indra/newview/skins/default/xui/da/menu_viewer.xml b/indra/newview/skins/default/xui/da/menu_viewer.xml
index 73986372ce..cfc60c8f84 100644
--- a/indra/newview/skins/default/xui/da/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/da/menu_viewer.xml
@@ -83,6 +83,7 @@
<menu_item_call label="Tag kopi" name="Take Copy"/>
<menu_item_call label="Opdatér ændringer til beholdning" name="Save Object Back to My Inventory"/>
<menu_item_call label="Opdater ændringer i indhold til objekt" name="Save Object Back to Object Contents"/>
+ <menu_item_call label="Returnér objekt" name="Return Object back to Owner"/>
</menu>
<menu label="Scripts" name="Scripts">
<menu_item_call label="Genoversæt scripts (Mono)" name="Mono"/>
@@ -96,6 +97,7 @@
<menu_item_check label="Vælg kun egne objekter" name="Select Only My Objects"/>
<menu_item_check label="Vis kun flytbare objekter" name="Select Only Movable Objects"/>
<menu_item_check label="Vælg ved at omkrandse" name="Select By Surrounding"/>
+ <menu_item_check label="Vis selektions afgrænsning" name="Show Selection Outlines"/>
<menu_item_check label="Vis skjulte objekter" name="Show Hidden Selection"/>
<menu_item_check label="Vis lys-radius for valgte" name="Show Light Radius for Selection"/>
<menu_item_check label="Vis pejlelys for valgte" name="Show Selection Beam"/>
@@ -116,6 +118,7 @@
<menu_item_call label="Rapporter misbrug" name="Report Abuse"/>
<menu_item_call label="Rapportér fejl" name="Report Bug"/>
<menu_item_call label="Om [APP_NAME]" name="About Second Life"/>
+ <menu_item_check label="Aktiver tips" name="Enable Hints"/>
</menu>
<menu label="Avanceret" name="Advanced">
<menu_item_call label="Stop animering af min avatar" name="Stop Animating My Avatar"/>
@@ -262,7 +265,7 @@
<menu_item_call label="Test web browser" name="Web Browser Test"/>
<menu_item_call label="Print info om valgt objekt" name="Print Selected Object Info"/>
<menu_item_call label="Hukommelse statistik" name="Memory Stats"/>
- <menu_item_check label="Dobbeltklik for auto-pilot" name="Double-Click Auto-Pilot"/>
+ <menu_item_check label="Dobbelt-klink Auto-pilot" name="Double-ClickAuto-Pilot"/>
<menu_item_check label="Dobeltklik for at teleportere" name="DoubleClick Teleport"/>
<menu_item_check label="Debug klik" name="Debug Clicks"/>
<menu_item_check label="Debug muse-hændelser" name="Debug Mouse Events"/>
@@ -274,6 +277,7 @@
<menu_item_call label="Gem til XML" name="Save to XML"/>
<menu_item_check label="Vis XUI navne" name="Show XUI Names"/>
<menu_item_call label="Send testbeskeder (IM)" name="Send Test IMs"/>
+ <menu_item_call label="Skriv navne-cache til disk" name="Flush Names Caches"/>
</menu>
<menu label="Avatar" name="Character">
<menu label="Grab Baked Texture" name="Grab Baked Texture">
diff --git a/indra/newview/skins/default/xui/da/notifications.xml b/indra/newview/skins/default/xui/da/notifications.xml
index a8849861cf..63c06ec27e 100644
--- a/indra/newview/skins/default/xui/da/notifications.xml
+++ b/indra/newview/skins/default/xui/da/notifications.xml
@@ -110,8 +110,8 @@ Vælg kun en genstand, og prøv igen.
<usetemplate name="okbutton" yestext="OK"/>
</notification>
<notification name="GrantModifyRights">
- At give redigerings rettigheder til en anden beboer, giver dem mulighed for at ændre, slette eller tage ALLE genstande, du måtte have i verden. Vær MEGET forsigtig når uddeler denne tilladelse.
-Ønsker du at ændre rettigheder for [FIRST_NAME] [LAST_NAME]?
+ Tildeling af ændre-rettigheder til andre beboere, tillader dem at ændre, slette eller tage ETHVERT objekt du måtte have. Vær MEGET forsigtig ved tildeling af denne rettighed.
+Ønsker du at give ændre-rettgheder til [NAME]?
<usetemplate name="okcancelbuttons" notext="Nej" yestext="Ja"/>
</notification>
<notification name="GrantModifyRightsMultiple">
@@ -120,7 +120,7 @@ Vælg kun en genstand, og prøv igen.
<usetemplate name="okcancelbuttons" notext="Nej" yestext="Ja"/>
</notification>
<notification name="RevokeModifyRights">
- Vil du tilbagekalde rettighederne for [FIRST_NAME] [LAST_NAME]?
+ Ønsker du at tilbagekalder ændre-rettigheder for [NAME]?
<usetemplate name="okcancelbuttons" notext="Nej" yestext="Ja"/>
</notification>
<notification name="RevokeModifyRightsMultiple">
@@ -202,14 +202,14 @@ Hvis media kun skal vises på en overflade, vælg &apos;Vælg overflade&apos; og
Overskrider vedhæftnings begrænsning på [MAX_ATTACHMENTS] objekter. Tag venligst en anden vedhæftning af først.
</notification>
<notification name="MustHaveAccountToLogIn">
- Ups! Noget var tomt.
-Du skal skrive både fornavn og efternavn på din figur.
+ Ups. Noget mangler at blive udfyldt.
+Du skal indtaste brugernavnet for din avatar.
-Du har brug for en konto for at logge ind i [SECOND_LIFE]. Vil du oprette en nu?
+Du skal bruge en konto for at benytte [SECOND_LIFE]. Ønsker du at oprette en konto nu?
<usetemplate name="okcancelbuttons" notext="Prøv igen" yestext="Lav ny konto"/>
</notification>
<notification name="InvalidCredentialFormat">
- Du skal indtaste både fornavn og efternavn i din avatars brugernavn felt og derefter logge på igen.
+ Du skal indtaste enten dit brugernavn eller både dit fornavn og efternavn for din avatar i brugernavn feltet, derefter log på igen.
</notification>
<notification name="AddClassified">
Annoncer vil vises i &apos;Annoncer&apos; sektionen i søge biblioteket og på [http://secondlife.com/community/classifieds secondlife.com] i en uge.
@@ -390,13 +390,6 @@ Dette er typisk en midlertidig fejl. Venligst rediger og gem igen om et par minu
[MESSAGE]
<usetemplate name="okcancelbuttons" notext="Afslut" yestext="Se PB &amp; Chat"/>
</notification>
- <notification label="Tilføj ven" name="AddFriend">
- Venner kan give tilladelse til at følge hinanden
-på Verdenskortet eller modtage status opdateringer.
-
-Tilbyd venskab til [NAME]?
- <usetemplate name="okcancelbuttons" notext="Annullér" yestext="OK"/>
- </notification>
<notification label="Tilføj ven" name="AddFriendWithMessage">
Venner kan give tilladelse til at følge hinanden
på Verdenskortet eller modtage status opdateringer.
@@ -440,12 +433,22 @@ Tilbyd venskab til [NAME]?
<button name="Cancel" text="Annullér"/>
</form>
</notification>
+ <notification name="RemoveFromFriends">
+ Ønsker du at fjerne [NAME] fra din venneliste?
+ </notification>
<notification name="ConfirmItemDeleteHasLinks">
Mindst en af genstandene har lænkede genstande der peger på den. Hvis du sletter denne genstand, vil lænkninger ikke virke mere. Det anbefales kraftigt at fjerne lænkninger først.
Er du sikker på at du vil slette disse genstande?
<usetemplate name="okcancelbuttons" notext="Annullér" yestext="OK"/>
</notification>
+ <notification name="DeedLandToGroupWithContribution">
+ Ved at dedikere denne parcel, vil gruppen skulle have og vedblive med at have nok kreditter til brug af land.
+Dedikeringen vil inkludere samtidige bidrag til gruppen fra &apos;[NAME]&apos;.
+Købsprisen for dette land er ikke refunderet til ejeren. Hvis en dedikeret parvel sælges, vil salgsprisen blive delt ligeligt mellem gruppe medlemmerne.
+
+Dediker disse [AREA] m² land til gruppen &apos;[GROUP_NAME]&apos;?
+ </notification>
<notification name="ErrorMessage">
<usetemplate name="okbutton" yestext="OK"/>
</notification>
@@ -651,6 +654,46 @@ Chat og personlige beskeder vil blive skjult. Personlige beskeder vil få din &a
<notification name="UnFreezeUser">
Fjern frysning af beboeren med hvilken besked?
</notification>
+ <notification name="SetDisplayNameSuccess">
+ Hej [DISPLAY_NAME]!
+
+Præcist som i virkeligheden tager det et stykke tid at vænne sig til et nyt navn. Det kan tage flere dage for [http://wiki.secondlife.com/wiki/Setting_your_display_name your name to update] i objekter, scripts, søgninger m.v.
+ </notification>
+ <notification name="SetDisplayNameBlocked">
+ Beklager, du kan ikke ændre dit visningsnavn. Hvis du mener dette skyldes en fejl, kontakt venligst support.
+ </notification>
+ <notification name="SetDisplayNameFailedLength">
+ Beklager, mavnet er for langt. Visningsnavne kan ikke indholde mere end [LENGTH] karakterer.
+
+Prøv venligst med et kortere navn.
+ </notification>
+ <notification name="SetDisplayNameFailedGeneric">
+ Beklager, vi kunne ikke sætte dit visningsnavn. Prøv venligst igen senere.
+ </notification>
+ <notification name="SetDisplayNameMismatch">
+ Visningsnavnene du angav matcher ikke. Prøv at taste ind igen.
+ </notification>
+ <notification name="AgentDisplayNameUpdateThresholdExceeded">
+ Beklager, du er nødt til at vente længere, inden du kan ændre visningsnavn.
+
+Se mere under http://wiki.secondlife.com/wiki/Setting_your_display_name
+
+Prøv venligst igen senere.
+ </notification>
+ <notification name="AgentDisplayNameSetBlocked">
+ Beklager, vi kunne ikke sætte dit valgte navn da det indholder et ikke tilladt ord.
+
+ Prøv med et andet navn.
+ </notification>
+ <notification name="AgentDisplayNameSetInvalidUnicode">
+ Visningsnavnet du prøver at angive indeholder ugyldige karakterer.
+ </notification>
+ <notification name="AgentDisplayNameSetOnlyPunctuation">
+ Dit vinsningsnavn skal indeholde andre bogstaver end tegnsætningstegn.
+ </notification>
+ <notification name="DisplayNameUpdate">
+ [OLD_NAME] ([SLID]) er nu kendt som [NEW_NAME].
+ </notification>
<notification name="OfferTeleport">
<form name="form">
<input name="message">
@@ -806,6 +849,7 @@ For at få adgang til voksen regioner, skal beboere være alders-checket, enten
<usetemplate ignoretext="Start min browser for at se min konto historik" name="okcancelignore" notext="Cancel" yestext="Go to page"/>
</notification>
<notification name="ConfirmQuit">
+ Er du sikker på at du vil afslutte?
<usetemplate ignoretext="Bekræft før jeg afslutter" name="okcancelignore" notext="Afslut ikke" yestext="Quit"/>
</notification>
<notification name="DeleteItems">
@@ -931,10 +975,10 @@ Henvis til dette fra en hjemmeside for at give andre nem adgang til denne lokati
Erstattet manglende tøj/kropsdele med standard.
</notification>
<notification name="FriendOnline">
- [NAME] er Online
+ [NAME] er logget på
</notification>
<notification name="FriendOffline">
- [NAME] er Offline
+ [NAME] er logget af
</notification>
<notification name="AddSelfFriend">
Selvom du nok er meget sød, kan du ikke tilføje dig selv som ven.
@@ -1073,7 +1117,10 @@ Prøv at vælge mindre stykker land.
<notification name="SystemMessage">
[MESSAGE]
</notification>
- <notification name="PaymentRecived">
+ <notification name="PaymentReceived">
+ [MESSAGE]
+ </notification>
+ <notification name="PaymentSent">
[MESSAGE]
</notification>
<notification name="EventNotification">
@@ -1082,7 +1129,7 @@ Prøv at vælge mindre stykker land.
[NAME]
[DATE]
<form name="form">
- <button name="Details" text="Beskrivelse"/>
+ <button name="Details" text="Detaljer"/>
<button name="Cancel" text="Annullér"/>
</form>
</notification>
@@ -1117,7 +1164,7 @@ Prøv venligst at geninstallere plugin eller kontakt leverandøren hvis probleme
De genstande du ejer på det valgte stykke land er blevet returneret til din beholdning.
</notification>
<notification name="OtherObjectsReturned">
- Genstandene på det valgte stykke land der er ejet af [NAME] er blevet returneret til hans eller hendes beholdning.
+ Objekterne på den valgte parcel, ejet af [NAME], er blevet returneret til vedkommendes beholdning.
</notification>
<notification name="OtherObjectsReturned2">
Objekterne i den valgte parcel, ejet af beboeren &apos;[NAME]&apos;, er blevet returneret til deres ejer.
@@ -1241,7 +1288,7 @@ Prøv igen om lidt.
No valid parcel could be found.
</notification>
<notification name="ObjectGiveItem">
- Et objekt med navnet [OBJECTFROMNAME] ejet af [NAME_SLURL] har givet dig denne/dette [OBJECTTYPE]:
+ Et object med navnet &lt;nolink&gt;[OBJECTFROMNAME]&lt;/nolink&gt; ejet af [NAME_SLURL] har givet dig denne [OBJECTTYPE]:
[ITEM_SLURL]
<form name="form">
<button name="Keep" text="Behold"/>
@@ -1305,6 +1352,11 @@ Prøv igen om lidt.
<notification name="FriendshipOffered">
Du har tilbudt venskab til [TO_NAME]
</notification>
+ <notification name="OfferFriendshipNoMessage">
+ [NAME_SLURL] tilbyder venskab.
+
+(Som udgangspunkt, vil du være i stand til at se den andens online status)
+ </notification>
<notification name="FriendshipAccepted">
[NAME] accepterede dit tilbud om venskab.
</notification>
@@ -1334,11 +1386,11 @@ Hvis du ikke forlader regionen, vil du blive logget af.
Hvis du ikke forlader regionen, vil du blive logget af.
</notification>
<notification name="LoadWebPage">
- Indlæs internetside [URL]?
+ Indlæas websiden [URL]?
[MESSAGE]
-Fra genstand: [OBJECTNAME], ejer: [NAME]?
+Fra objekt: &lt;nolink&gt;[OBJECTNAME]&lt;/nolink&gt;, ejer: [NAME]?
<form name="form">
<button name="Gotopage" text="Gå til side"/>
<button name="Cancel" text="Afbryd"/>
@@ -1354,9 +1406,10 @@ Fra genstand: [OBJECTNAME], ejer: [NAME]?
Den genstand du prøver at tage på benytter en funktion din klient ikke kan forstå. Upgradér venligst din version af [APP_NAME] for at kunne tage denne genstand på.
</notification>
<notification name="ScriptQuestion">
- &apos;[OBJECTNAME]&apos;, en genstand, ejet af &apos;[NAME]&apos;, vil gerne:
- [QUESTIONS]
-Er det iorden?
+ &apos;&lt;nolink&gt;[OBJECTNAME]&lt;/nolink&gt;&apos;, et objekt ved ejet af &apos;[NAME]&apos;, ønsker at:
+
+[QUESTIONS]
+Er dette OK?
<form name="form">
<button name="Yes" text="Ja"/>
<button name="No" text="Nej"/>
@@ -1364,12 +1417,12 @@ Er det iorden?
</form>
</notification>
<notification name="ScriptQuestionCaution">
- Et objekt med navnet &apos;[OBJECTNAME]&apos;, ejet af &apos;[NAME]&apos;, ønsker at:
+ Et objeckt med navn &apos;&lt;nolink&gt;[OBJECTNAME]&lt;/nolink&gt;&apos;, ejet af &apos;[NAME]&apos; ønsker at:
[QUESTIONS]
-Hvis du ikke stoler på dette objekt og dets skaber, bør du afvise denne forespørgsel.
+Hvis du ikke stoler på dette objekt og dets skaber, bør du afvise dette ønske.
-Tillad denne anmodning?
+Opfyld dette ønske?
<form name="form">
<button name="Grant" text="Imødekom"/>
<button name="Deny" text="Afvis"/>
@@ -1384,7 +1437,7 @@ Tillad denne anmodning?
</form>
</notification>
<notification name="ScriptDialogGroup">
- [GROUPNAME]&apos;s &apos;[TITLE]&apos;
+ [GROUPNAME]&apos;s &apos;&lt;nolink&gt;[TITLE]&lt;/nolink&gt;&apos;
[MESSAGE]
<form name="form">
<button name="Ignore" text="Ignorér"/>
@@ -1421,13 +1474,13 @@ Klik på Acceptér for at deltage eller Afvis for at afvise invitationen. Klik p
</form>
</notification>
<notification name="AutoUnmuteByIM">
- [NAME] fik tilsendt en personlig besked og er dermed automatisk ikke mere blokeret.
+ [NAME] har fået sendt en besked og blokering er derfor automatisk blevet fjernet.
</notification>
<notification name="AutoUnmuteByMoney">
- [NAME] blev givet penge og er dermed automatisk ikke mere blokeret.
+ [NAME] har fået givet penge og blokering er derfor automatisk blevet fjernet.
</notification>
<notification name="AutoUnmuteByInventory">
- [NAME] blev tilbudt en genstand og er dermed automatisk ikke mere blokeret.
+ [NAME] er blevet tilbud noget fra beholdning og blokering er derfor automatisk blevet fjernet.
</notification>
<notification name="VoiceInviteGroup">
[NAME] har has sluttet sig til stemme-chaten i gruppen [GROUP].
@@ -1655,6 +1708,37 @@ vil have lyden slukket - selv efter de har forladt kaldet.
Sluk for alles lyd?
<usetemplate ignoretext="Bekræft før jeg slukker for alle deltageres lyd i gruppe-kald" name="okcancelignore" notext="Annullér" yestext="Ok"/>
</notification>
+ <notification label="Chat" name="HintChat">
+ For at deltage i samtalen tast tekst ind i chat feltet nedenfor.
+ </notification>
+ <notification label="Stå op" name="HintSit">
+ For at rejse dig op og forlad siddeposition, tryk på &quot;Stå op&quot; knappen.
+ </notification>
+ <notification label="Undersøg verden" name="HintDestinationGuide">
+ Destinationsguiden indeholder tusinder af nye steder der kan opleves. Vælg venligst et sted og vælg Teleport for at komme derhen.
+ </notification>
+ <notification label="Side panel" name="HintSidePanel">
+ Få hurtig tilgang til din beholdning, sæt, profiler og andet i dette side panel.
+ </notification>
+ <notification label="Flyt" name="HintMove">
+ For at gå eller løbe, åben Flyt panelet for neden og brug pilene til at navigere. Du kan også bruge pile-tasterne på dit tastatur.
+ </notification>
+ <notification label="Visningsnavn" name="HintDisplayName">
+ Angiv dit konfigurérbare visningsnavn her. Dette er i tillæg til dit unikke brugernavn, som ikke kan ændres. Du kan ændre hvordan du ser andre beboeres navne i dine indstillinger.
+ </notification>
+ <notification label="Beholdning" name="HintInventory">
+ Undersøg din beholdning for at finde ting. Nyeste genstand findes lettes under fanen &quot;Nye ting&quot;
+ </notification>
+ <notification label="Der er kommet Linden Dollars" name="HintLindenDollar">
+ Her er din nuværende balance af L$. Klik på Køb L$ for at købe flere Linden dollars.
+ </notification>
+ <notification name="PopupAttempt">
+ En pop-up blev hindret i at blive vist.
+ <form name="form">
+ <ignore name="ignore" text="Tillad alle pop-ups"/>
+ <button name="open" text="Åben pop-up vindue"/>
+ </form>
+ </notification>
<global name="UnsupportedGLRequirements">
Det ser ikke ud til at din hardware opfylder minimumskravene til [APP_NAME]. [APP_NAME] kræver et OpenGL grafikkort som understøter &apos;multitexture&apos;. Check eventuelt om du har de nyeste drivere for grafikkortet, og de nyeste service-packs og patches til dit operativsystem.
diff --git a/indra/newview/skins/default/xui/da/panel_edit_profile.xml b/indra/newview/skins/default/xui/da/panel_edit_profile.xml
index 27a6000419..80b20f15e9 100644
--- a/indra/newview/skins/default/xui/da/panel_edit_profile.xml
+++ b/indra/newview/skins/default/xui/da/panel_edit_profile.xml
@@ -23,6 +23,14 @@
<scroll_container name="profile_scroll">
<panel name="scroll_content_panel">
<panel name="data_panel">
+ <text name="display_name_label" value="Visningsnavn:"/>
+ <text name="solo_username_label" value="Bugernavn:"/>
+ <button name="set_name" tool_tip="Sæt visningsnavn"/>
+ <text name="solo_user_name" value="Hamilton Hitchings"/>
+ <text name="user_name" value="Hamilton Hitchings"/>
+ <text name="user_name_small" value="Hamilton Hitchings"/>
+ <text name="user_label" value="Brugernavn:"/>
+ <text name="user_slid" value="hamilton.linden"/>
<panel name="lifes_images_panel">
<icon label="" name="2nd_life_edit_icon" tool_tip="Klik for at vælge et billede"/>
</panel>
@@ -39,7 +47,7 @@
<text name="my_account_link" value="[[URL] Go to My Dashboard]"/>
<text name="title_partner_text" value="Min partner:"/>
<panel name="partner_data_panel">
- <name_box initial_value="(henter)" name="partner_text"/>
+ <text initial_value="(henter)" name="partner_text"/>
</panel>
<text name="partner_edit_link" value="[[URL] Edit]"/>
</panel>
diff --git a/indra/newview/skins/default/xui/da/panel_group_land_money.xml b/indra/newview/skins/default/xui/da/panel_group_land_money.xml
index efad4d0c34..49d415e515 100644
--- a/indra/newview/skins/default/xui/da/panel_group_land_money.xml
+++ b/indra/newview/skins/default/xui/da/panel_group_land_money.xml
@@ -24,6 +24,7 @@
<scroll_list.columns label="Region" name="location"/>
<scroll_list.columns label="Type" name="type"/>
<scroll_list.columns label="Areal" name="area"/>
+ <scroll_list.columns label="Skjult" name="hidden"/>
</scroll_list>
<text name="total_contributed_land_label">
Totalt bidrag:
diff --git a/indra/newview/skins/default/xui/da/panel_login.xml b/indra/newview/skins/default/xui/da/panel_login.xml
index d4bf9a7d78..268f138185 100644
--- a/indra/newview/skins/default/xui/da/panel_login.xml
+++ b/indra/newview/skins/default/xui/da/panel_login.xml
@@ -14,7 +14,7 @@
<text name="username_text">
Brugernavn:
</text>
- <line_editor label="Brugernavn" name="username_edit" tool_tip="[SECOND_LIFE] Brugernavn"/>
+ <line_editor label="bobsmith12 eller Steller Sunshine" name="username_edit" tool_tip="Det brugernavn du valgte da du registrerede, som f.eks. bobsmith12 eller Steller Sunshine"/>
<text name="password_text">
Password:
</text>
@@ -34,7 +34,7 @@
Opret bruger
</text>
<text name="forgot_password_text">
- Glemt navn eller password?
+ Har du glemt brugernavn eller password?
</text>
<text name="login_help">
Hjælp til login
diff --git a/indra/newview/skins/default/xui/da/panel_place_profile.xml b/indra/newview/skins/default/xui/da/panel_place_profile.xml
index 05ef22328f..8dd0fb2d21 100644
--- a/indra/newview/skins/default/xui/da/panel_place_profile.xml
+++ b/indra/newview/skins/default/xui/da/panel_place_profile.xml
@@ -76,7 +76,7 @@
<text name="region_rating_label" value="Rating:"/>
<text name="region_rating" value="Voksent"/>
<text name="region_owner_label" value="Ejer:"/>
- <text name="region_owner" value="moose Van Moose"/>
+ <text name="region_owner" value="moose Van Moose extra long name moose"/>
<text name="region_group_label" value="Gruppe:"/>
<text name="region_group">
The Mighty Moose of mooseville soundvillemoose
@@ -89,6 +89,7 @@
<text name="estate_name_label" value="Estate:"/>
<text name="estate_rating_label" value="Rating:"/>
<text name="estate_owner_label" value="Ejer:"/>
+ <text name="estate_owner" value="Tester brugernavn længde med langt navn"/>
<text name="covenant_label" value="Regler:"/>
</panel>
</accordion_tab>
diff --git a/indra/newview/skins/default/xui/da/panel_places.xml b/indra/newview/skins/default/xui/da/panel_places.xml
index ca3d7c71bb..fe8ca69f34 100644
--- a/indra/newview/skins/default/xui/da/panel_places.xml
+++ b/indra/newview/skins/default/xui/da/panel_places.xml
@@ -21,7 +21,7 @@
<button label="Redigér" name="edit_btn" tool_tip="Redigér landemærke information"/>
</layout_panel>
<layout_panel name="overflow_btn_lp">
- <button label="▼" name="overflow_btn" tool_tip="Vis flere valg"/>
+ <menu_button label="▼" name="overflow_btn" tool_tip="Vis flere valg"/>
</layout_panel>
</layout_stack>
<layout_stack name="bottom_bar_ls3">
diff --git a/indra/newview/skins/default/xui/da/panel_preferences_general.xml b/indra/newview/skins/default/xui/da/panel_preferences_general.xml
index 6a85cf4aae..9c0cb583af 100644
--- a/indra/newview/skins/default/xui/da/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/da/panel_preferences_general.xml
@@ -42,9 +42,10 @@
<radio_item label="Vis" name="radio2" value="1"/>
<radio_item label="Vis et øjeblik" name="radio3" value="2"/>
</radio_group>
- <check_box label="Vis mit navn" name="show_my_name_checkbox1"/>
- <check_box initial_value="true" label="Små avatar navne" name="small_avatar_names_checkbox"/>
- <check_box label="Gruppetitler" name="show_all_title_checkbox1"/>
+ <check_box label="Mit navn" name="show_my_name_checkbox1"/>
+ <check_box label="Brugernavne" name="show_slids" tool_tip="Vis brugernavne, som bobsmith123"/>
+ <check_box label="Gruppe titler" name="show_all_title_checkbox1" tool_tip="Vis hgruppetitler, som f.eks. administrator eller medlem"/>
+ <check_box label="Fremhæv venner" name="show_friends" tool_tip="Fremhæv navne-tags for dine venner"/>
<text name="effects_color_textbox">
Farve til mine effekter:
</text>
@@ -59,6 +60,7 @@
<combo_box.item label="30 minutter" name="item3"/>
<combo_box.item label="aldrig" name="item4"/>
</combo_box>
+ <check_box label="Vis visningsnavne" name="display_names_check" tool_tip="Vælg for at bruge visningsnavne i chat, IM, navne-tags m.v."/>
<text name="text_box3">
Optaget autosvar:
</text>
diff --git a/indra/newview/skins/default/xui/da/panel_preferences_setup.xml b/indra/newview/skins/default/xui/da/panel_preferences_setup.xml
index 38bc9c0a2a..553d21d597 100644
--- a/indra/newview/skins/default/xui/da/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/da/panel_preferences_setup.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Opsætning" name="Input panel">
- <button label="Andre enheder" name="joystick_setup_button"/>
<text name="Mouselook:">
Første person:
</text>
@@ -37,10 +36,11 @@
<radio_item label="Benyt min browser(IE, Firefox, Safari)" name="external" tool_tip="Brug systemets standard web browser til hjælp, web links, m.v. Ikke anbefalet hvis du kører i fuld-skærm." value="1"/>
<radio_item label="Benyt den indbyggede browser" name="internal" tool_tip="Brug den indbyggede web browser til hjælp, web links m.v. Denne browser åbner et nyt vindue i [APP_NAME]." value=""/>
</radio_group>
- <check_box label="Aktivér plugins" name="browser_plugins_enabled"/>
- <check_box label="Acceptér cookies" name="cookies_enabled"/>
- <check_box label="Aktivér Javascript" name="browser_javascript_enabled"/>
- <check_box label="Aktivér web proxy" name="web_proxy_enabled"/>
+ <check_box initial_value="true" label="Aktivér plugins" name="browser_plugins_enabled"/>
+ <check_box initial_value="true" label="Acceptér cookies" name="cookies_enabled"/>
+ <check_box initial_value="true" label="Aktivér Javascript" name="browser_javascript_enabled"/>
+ <check_box initial_value="fra" label="Tilad media browser pop-ups" name="media_popup_enabled"/>
+ <check_box initial_value="false" label="Aktivér web proxy" name="web_proxy_enabled"/>
<text name="Proxy location">
Proxy placering:
</text>
diff --git a/indra/newview/skins/default/xui/da/panel_profile.xml b/indra/newview/skins/default/xui/da/panel_profile.xml
index b2d1e9791a..b8b99a9c21 100644
--- a/indra/newview/skins/default/xui/da/panel_profile.xml
+++ b/indra/newview/skins/default/xui/da/panel_profile.xml
@@ -42,7 +42,7 @@
<button label="Teleportér" name="teleport" tool_tip="Tilbyd teleport"/>
</layout_panel>
<layout_panel name="overflow_btn_lp">
- <button label="▼" name="overflow_btn" tool_tip="Betal eller del beholdning med denne beboer"/>
+ <menu_button label="▼" name="overflow_btn" tool_tip="Betal eller del beholdning med denne beboer"/>
</layout_panel>
</layout_stack>
</layout_panel>
diff --git a/indra/newview/skins/default/xui/da/panel_profile_view.xml b/indra/newview/skins/default/xui/da/panel_profile_view.xml
index 23b9d3ba83..5e0a51eb28 100644
--- a/indra/newview/skins/default/xui/da/panel_profile_view.xml
+++ b/indra/newview/skins/default/xui/da/panel_profile_view.xml
@@ -6,8 +6,14 @@
<string name="status_offline">
Offline
</string>
- <text_editor name="user_name" value="(Henter...)"/>
+ <text name="display_name_label" value="Visningsnavn:"/>
+ <text name="solo_username_label" value="Brugernavn:"/>
<text name="status" value="Online"/>
+ <text name="user_name_small" value="Se på mig med dette enormt ekstremt super lange navn"/>
+ <text name="user_name" value="Jack Linden"/>
+ <button name="copy_to_clipboard" tool_tip="Kopiér til udskriftsholder"/>
+ <text name="user_label" value="Brugernavn:"/>
+ <text name="user_slid" value="jack.linden"/>
<tab_container name="tabs">
<panel label="PROFIL" name="panel_profile"/>
<panel label="FAVORITTER" name="panel_picks"/>
diff --git a/indra/newview/skins/default/xui/da/role_actions.xml b/indra/newview/skins/default/xui/da/role_actions.xml
index 5ec90a759a..7e581200a5 100644
--- a/indra/newview/skins/default/xui/da/role_actions.xml
+++ b/indra/newview/skins/default/xui/da/role_actions.xml
@@ -1,76 +1,73 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<role_actions>
<action_set description="Disse rettigheder inkluderer adgang til at tilføje og fjerne gruppe medlemmer og tillade nye medlemmer at melde sig ind uden invitation" name="Membership">
- <action description="Invitér personer til denne gruppe" longdescription="Invitér personer til denne gruppe via &apos;Invitér ny person...&apos; knappen i fanen: medlemmer &amp; roller &gt; underfanen: medlemmer" name="member invite"/>
- <action description="Fjern medlemmer fra denne gruppe" longdescription="Fjern medlemmer i denne gruppe via &apos;Fjern fra gruppe&apos; knappen i fanen: medlemmer &amp; roller &gt; underfanen: medlemmer. En ejer kan fjerne alle undtagen en anden ejer. Hvis du ikke er en ejer, kan et medlem kun fjernes fra gruppen hvis, og kun hvis, medlemmet kun findes i Alle rollen, og ikke i andre roller. for at fjerne medlemmer fra roller, skal du have rettigheden &apos;Fjern medlemmer fra roller" name="member eject"/>
- <action description="Åben eller luk for &apos;fri tilmelding&apos; og ændre &apos;tilmeldingsgebyr&apos;" longdescription="Åben for &apos;fri tilmelding&apos; så alle kan blive medlem af gruppen, eller luk for &apos;fri tilmelding&apos; så kun inveterede kan blive medlem. ændre &apos;tilmeldingsgebyr&apos; i gruppe opsætningsbilledet sektionen i Generelt fanen" name="member options"/>
+ <action description="Invitér personer til denne gruppe" longdescription="Invitér personer til denne gruppe via &apos;Invitér ny person...&apos; knappen i fanen: medlemmer &amp; roller &gt; underfanen: medlemmer" name="member invite" value="1"/>
+ <action description="Fjern medlemmer fra denne gruppe" longdescription="Fjern medlemmer i denne gruppe via &apos;Fjern fra gruppe&apos; knappen i fanen: medlemmer &amp; roller &gt; underfanen: medlemmer. En ejer kan fjerne alle undtagen en anden ejer. Hvis du ikke er en ejer, kan et medlem kun fjernes fra gruppen hvis, og kun hvis, medlemmet kun findes i Alle rollen, og ikke i andre roller. for at fjerne medlemmer fra roller, skal du have rettigheden &apos;Fjern medlemmer fra roller" name="member eject" value="2"/>
+ <action description="Åben eller luk for &apos;fri tilmelding&apos; og ændre &apos;tilmeldingsgebyr&apos;" longdescription="Åben for &apos;fri tilmelding&apos; så alle kan blive medlem af gruppen, eller luk for &apos;fri tilmelding&apos; så kun inveterede kan blive medlem. ændre &apos;tilmeldingsgebyr&apos; i gruppe opsætningsbilledet sektionen i Generelt fanen" name="member options" value="3"/>
</action_set>
<action_set description="Disse rettigheder inkluderer adgang til at tilføje, fjerne og ændre gruppe-roller, tilføje og fjerne medlemmer i roller, og give rettigheder til roller" name="Roles">
- <action description="Opret nye roller" longdescription="Opret nye roller i fanen: Medlemmer &amp; roller &gt; under-fanen: Roller." name="role create"/>
- <action description="Slet roller" longdescription="Slet roller i roller i fanen: Medlemmer &amp; roller &gt; under-fanen: Roller." name="role delete"/>
- <action description="Ændre rolle navne, titler, beskrivelser og angivelse af om rollemedlemmer kan ses af andre udenfor gruppen" longdescription="Ændre rolle navne, titler, beskrivelser og angivelse af om rollemedlemmer kan ses af andre udenfor gruppen. Dette håndteres i bunden af fanen:: Medlemmer &amp; roller &gt; under-fanen: Roller efter at have valgt en rolle." name="role properties"/>
- <action description="Tildel andre samme roller som dig selv" longdescription="Tildel andre medlemmer til roller i Tildelte roller sektionen på fanen: Medlemmer &amp; roller &gt; under-fanen: Medlemmer. Et medlem med denne rettighed kan kun tildele andre medlemmer en rolle som tildeleren allerede selv har." name="role assign member limited"/>
- <action description="Tildele medlemmer enhver rolle" longdescription="Tildel andre medlemmer til en hvilken som helst rolle i Tildelte roller sektionen på fanen: Medlemmer &amp; roller &gt; under-fanen: Medlemmer. *ADVARSEL* Ethvert medlem i en rolle med denne rettighed kan tildele sig selv - og enhver anden - roller som giver dem flere rettigheder end de havde tidligere, og dermed potentielt få næsten samme magt som ejer. Vær sikker på at vide hvad du ør inden du tildeler denne rettighed." name="role assign member"/>
- <action description="Fjern medlemmer fra roller" longdescription="Fjern medlemmer fra roller i in Tildelte roller sektionen på fanen: Medlemmer &amp; roller &gt; under-fanen: Medlemmer. Ejere kan ikke fjernes." name="role remove member"/>
- <action description="Tildel og fjern rettigheder for roller" longdescription="Tildel og fjern rettigheder for roller i tilladte rettigheder sektionen på fanen: Medlemmer &amp; roller &gt; under-fanen: Roller. *ADVARSEL* Ethvert medlem i en rolle med denne rettighed kan tildele sig selv - og enhver anden - rettigheder som giver dem flere rettigheder end de havde tidligere, og dermed potentielt få næsten samme magt som ejer. Vær sikker på at vide hvad du gør inden du tildeler denne rettighed." name="role change actions"/>
+ <action description="Opret nye roller" longdescription="Opret nye roller i fanen: Medlemmer &amp; roller &gt; under-fanen: Roller." name="role create" value="4"/>
+ <action description="Slet roller" longdescription="Slet roller i roller i fanen: Medlemmer &amp; roller &gt; under-fanen: Roller." name="role delete" value="5"/>
+ <action description="Ændre rolle navne, titler, beskrivelser og angivelse af om rollemedlemmer kan ses af andre udenfor gruppen" longdescription="Ændre rolle navne, titler, beskrivelser og angivelse af om rollemedlemmer kan ses af andre udenfor gruppen. Dette håndteres i bunden af fanen:: Medlemmer &amp; roller &gt; under-fanen: Roller efter at have valgt en rolle." name="role properties" value="6"/>
+ <action description="Tildel andre samme roller som dig selv" longdescription="Tildel andre medlemmer til roller i Tildelte roller sektionen på fanen: Medlemmer &amp; roller &gt; under-fanen: Medlemmer. Et medlem med denne rettighed kan kun tildele andre medlemmer en rolle som tildeleren allerede selv har." name="role assign member limited" value="7"/>
+ <action description="Tildele medlemmer enhver rolle" longdescription="Tildel andre medlemmer til en hvilken som helst rolle i Tildelte roller sektionen på fanen: Medlemmer &amp; roller &gt; under-fanen: Medlemmer. *ADVARSEL* Ethvert medlem i en rolle med denne rettighed kan tildele sig selv - og enhver anden - roller som giver dem flere rettigheder end de havde tidligere, og dermed potentielt få næsten samme magt som ejer. Vær sikker på at vide hvad du ør inden du tildeler denne rettighed." name="role assign member" value="8"/>
+ <action description="Fjern medlemmer fra roller" longdescription="Fjern medlemmer fra roller i in Tildelte roller sektionen på fanen: Medlemmer &amp; roller &gt; under-fanen: Medlemmer. Ejere kan ikke fjernes." name="role remove member" value="9"/>
+ <action description="Tildel og fjern rettigheder for roller" longdescription="Tildel og fjern rettigheder for roller i tilladte rettigheder sektionen på fanen: Medlemmer &amp; roller &gt; under-fanen: Roller. *ADVARSEL* Ethvert medlem i en rolle med denne rettighed kan tildele sig selv - og enhver anden - rettigheder som giver dem flere rettigheder end de havde tidligere, og dermed potentielt få næsten samme magt som ejer. Vær sikker på at vide hvad du gør inden du tildeler denne rettighed." name="role change actions" value="10"/>
</action_set>
<action_set description="Disse rettigheder inkluderer adgang til at ændre denne gruppes identitetsoplysninger, som f.eks. om gruppen kan ses af andre, gruppens fundats og billede." name="Group Identity">
- <action description="Ændre fundats, billede og &apos;Vis i søgning&apos;" longdescription="Ændre fundats og &apos;Vis i søgning&apos;. Dette gøres under fanen Generelt." name="group change identity"/>
+ <action description="Ændre fundats, billede og &apos;Vis i søgning&apos;" longdescription="Ændre fundats og &apos;Vis i søgning&apos;. Dette gøres under fanen Generelt." name="group change identity" value="11"/>
</action_set>
<action_set description="Disse rettigheder inkluderer adgang til dedikere, ændre og sælge land fra denne gruppes besiddelser. For at åbne &apos;Om land...&apos; vinduet, højre-klik på jorden og vælg &apos;Om land...&apos;, eller klik på &apos;Om land...&apos; i &apos;Verden&apos; menuen." name="Parcel Management">
- <action description="Dedikér eller køb land til gruppen" longdescription="Dedikér eller køb land til gruppen. Dette gøres i fanen Generelt i &apos;Om land...&apos;." name="land deed"/>
- <action description="Forlad land og overgiv det til guvernør Linden" longdescription="Forlad land og overgiv det til guvernør Linden. *ADVARSEL* Ethvert medlem med en rolle med denne rettighed kan overdrage gruppe-ejet land via fanen Generelt i &apos;Om land...&apos; til Lindens ejerskab uden salg! Vær sikker på at vide hvad du ør inden du tildeler denne rettighed." name="land release"/>
- <action description="Sæt land til salg" longdescription="Sæt land til salg. *ADVARSEL* Ethvert medlem med en rolle med denne rettighed kan sælge gruppe-ejet land via fanen Generelt i &apos;Om land...&apos;! Vær sikker på at vide hvad du ør inden du tildeler denne rettighed." name="land set sale info"/>
- <action description="Opdel og saml parceller" longdescription="Opdel og saml parceller. Dette gøres ved at højreklikke på jorden og vælge &apos;Redigér terræn&apos;" name="land divide join"/>
+ <action description="Dedikér eller køb land til gruppen" longdescription="Dedikér eller køb land til gruppen. Dette gøres i fanen Generelt i &apos;Om land...&apos;." name="land deed" value="12"/>
+ <action description="Forlad land og overgiv det til guvernør Linden" longdescription="Forlad land og overgiv det til guvernør Linden. *ADVARSEL* Ethvert medlem med en rolle med denne rettighed kan overdrage gruppe-ejet land via fanen Generelt i &apos;Om land...&apos; til Lindens ejerskab uden salg! Vær sikker på at vide hvad du ør inden du tildeler denne rettighed." name="land release" value="13"/>
+ <action description="Sæt land til salg" longdescription="Sæt land til salg. *ADVARSEL* Ethvert medlem med en rolle med denne rettighed kan sælge gruppe-ejet land via fanen Generelt i &apos;Om land...&apos;! Vær sikker på at vide hvad du ør inden du tildeler denne rettighed." name="land set sale info" value="14"/>
+ <action description="Opdel og saml parceller" longdescription="Opdel og saml parceller. Dette gøres ved at højreklikke på jorden og vælge &apos;Redigér terræn&apos;" name="land divide join" value="15"/>
</action_set>
<action_set description="Disse rettigheder inkluderer adgang til at ændre parcel navn og en række parametre om f.eks. landingspunkt, teleports m.v.." name="Parcel Identity">
- <action description="Angive om sted skal vises i &apos;vis i Søg steder&apos; og angivelse af kategori" longdescription="Angive om sted skal vises i &apos;vis i Søg steder&apos; og angivelse af kategori i &apos;Om land...&apos; &gt; Indstillinger fanen." name="land find places"/>
- <action description="Ændre parcel navn, beskrivelse, og &apos;Vis i Søg&apos; opsætning" longdescription="Ændre parcel navn, beskrivelse, og &apos;Vis i Søg&apos; opsætning. Dette håndteres i &apos;Om land...&apos;&gt; Opsætning fanen." name="land change identity"/>
- <action description="Sæt landingspunkt og teleport muligheder" longdescription="På en gruppe-ejet parcel kan medlemmer, med en rolle med denne rettighed, sætte landingspunktet og dermed angive hvor indkommende teleporte skal ankomme og desuden angive dealjer om teleporte. Dette håndteres i &apos;Om land...&apos;&gt; Opsætning fanen." name="land set landing point"/>
+ <action description="Angive om sted skal vises i &apos;vis i Søg steder&apos; og angivelse af kategori" longdescription="Angive om sted skal vises i &apos;vis i Søg steder&apos; og angivelse af kategori i &apos;Om land...&apos; &gt; Indstillinger fanen." name="land find places" value="17"/>
+ <action description="Ændre parcel navn, beskrivelse, og &apos;Vis i Søg&apos; opsætning" longdescription="Ændre parcel navn, beskrivelse, og &apos;Vis i Søg&apos; opsætning. Dette håndteres i &apos;Om land...&apos;&gt; Opsætning fanen." name="land change identity" value="18"/>
+ <action description="Sæt landingspunkt og teleport muligheder" longdescription="På en gruppe-ejet parcel kan medlemmer, med en rolle med denne rettighed, sætte landingspunktet og dermed angive hvor indkommende teleporte skal ankomme og desuden angive dealjer om teleporte. Dette håndteres i &apos;Om land...&apos;&gt; Opsætning fanen." name="land set landing point" value="19"/>
</action_set>
<action_set description="Disse rettigheder inkluderer adgang til at opsætte parcel indstillinger som f.eks. &apos;Lave objekter&apos;, &apos;Redigere terræn&apos;, samt musik og media indstillinger." name="Parcel Settings">
- <action description="Ændre musik og media indstillinger" longdescription="Ændre oplysninger om streaming musik og film i &apos;Om land...&apos; &gt; Media fanen." name="land change media"/>
- <action description="Ændre rettighed til &apos;Redigere terræn&apos;" longdescription="Ændre rettighed til &apos;Redigere terræn&apos;. *ADVARSEL*: Redigere terræn&apos; kan give alle og enhver ret til at ændre terræn og opsætte og flytte Linden planter. Vær sikker på at vide hvad du ør inden du tildeler denne rettighed." name="land edit"/>
- <action description="Ændre diverse andre indstillinger i &apos;Om land...&apos;&gt; indstillinger fanen" longdescription="Giv adgang til at ændre &apos;Sikker (ingen skade)&apos;, &apos;Flyve&apos;, og tillad andre beboere at: &apos;Lave objekter&apos;, &apos;Redigere terræn&apos;, &apos;Lave landemærker&apos;, og &apos;Køre scripts&apos; på gruppe-ejet land via About Land &gt; Indstillinger fanen." name="land options"/>
+ <action description="Ændre musik og media indstillinger" longdescription="Ændre oplysninger om streaming musik og film i &apos;Om land...&apos; &gt; Media fanen." name="land change media" value="20"/>
+ <action description="Ændre rettighed til &apos;Redigere terræn&apos;" longdescription="Ændre rettighed til &apos;Redigere terræn&apos;. *ADVARSEL*: Redigere terræn&apos; kan give alle og enhver ret til at ændre terræn og opsætte og flytte Linden planter. Vær sikker på at vide hvad du ør inden du tildeler denne rettighed." name="land edit" value="21"/>
+ <action description="Ændre diverse andre indstillinger i &apos;Om land...&apos;&gt; indstillinger fanen" longdescription="Giv adgang til at ændre &apos;Sikker (ingen skade)&apos;, &apos;Flyve&apos;, og tillad andre beboere at: &apos;Lave objekter&apos;, &apos;Redigere terræn&apos;, &apos;Lave landemærker&apos;, og &apos;Køre scripts&apos; på gruppe-ejet land via About Land &gt; Indstillinger fanen." name="land options" value="22"/>
</action_set>
<action_set description="Disse rettigheder inkluderer adgang til at medlemmer kan omgå restriktioner på gruppe-ejede parceller." name="Parcel Powers">
- <action description="Tillad altid &apos;Rediger Terræn&apos;" longdescription="Medlemmer med denne rolle har adgang til at redigere terræn på gruppe-ejede parceller, også selvom denne mulighed ikke er aktiveret på &apos;Om land...&apos; &gt; Indstillinger fanen." name="land allow edit land"/>
- <action description="Tillad altid at &apos;Flyve&apos;" longdescription="Medlemmer med denne rolle har adgang til at flyve på gruppe-ejede parceller, også selvom denne mulighed ikke er aktiveret på &apos;Om land...&apos; &gt; Indstillinger fanen." name="land allow fly"/>
- <action description="Tillad altid &apos;Lave objekter&apos;" longdescription="Medlemmer med denne rolle har adgang til at lave nye objekter på gruppe-ejede parceller, også selvom denne mulighed ikke er aktiveret på &apos;Om land...&apos; &gt; Indstillinger fanen." name="land allow create"/>
- <action description="Tillad altid at &apos;Lave landemærker&apos;" longdescription="Medlemmer med denne rolle har adgang til at lave landemærker på gruppe-ejede parceller, også selvom denne mulighed ikke er aktiveret på &apos;Om land...&apos; &gt; Indstillinger fanen." name="land allow landmark"/>
- <action description="Tillad altid &apos;sæt til hjem&apos; på gruppe-ejet land" longdescription="Medlemmer med denne rolle har adgang til at benytte &apos;Verden&apos; menuen og vælge &apos;sæt til hjem&apos; på en parcel der er dedikeret til gruppen." name="land allow set home"/>
+ <action description="Tillad altid &apos;Rediger Terræn&apos;" longdescription="Medlemmer med denne rolle har adgang til at redigere terræn på gruppe-ejede parceller, også selvom denne mulighed ikke er aktiveret på &apos;Om land...&apos; &gt; Indstillinger fanen." name="land allow edit land" value="23"/>
+ <action description="Tillad altid at &apos;Flyve&apos;" longdescription="Medlemmer med denne rolle har adgang til at flyve på gruppe-ejede parceller, også selvom denne mulighed ikke er aktiveret på &apos;Om land...&apos; &gt; Indstillinger fanen." name="land allow fly" value="24"/>
+ <action description="Tillad altid &apos;Lave objekter&apos;" longdescription="Medlemmer med denne rolle har adgang til at lave nye objekter på gruppe-ejede parceller, også selvom denne mulighed ikke er aktiveret på &apos;Om land...&apos; &gt; Indstillinger fanen." name="land allow create" value="25"/>
+ <action description="Tillad altid at &apos;Lave landemærker&apos;" longdescription="Medlemmer med denne rolle har adgang til at lave landemærker på gruppe-ejede parceller, også selvom denne mulighed ikke er aktiveret på &apos;Om land...&apos; &gt; Indstillinger fanen." name="land allow landmark" value="26"/>
+ <action description="Tillad altid &apos;sæt til hjem&apos; på gruppe-ejet land" longdescription="Medlemmer med denne rolle har adgang til at benytte &apos;Verden&apos; menuen og vælge &apos;sæt til hjem&apos; på en parcel der er dedikeret til gruppen." name="land allow set home" value="28"/>
+ <action description="Tillad &apos;Event Hosting&apos; på gruppe ejet land" longdescription="Medlemmer med denne rolle kan vælge gruppe ejede parceller som sted når der afholdes et event." name="land allow host event" value="41"/>
</action_set>
<action_set description="Disse rettigheder inkluderer adgang til at medlemmer kan tillade eller forbyde adgang til gruppe-ejede parceller, inkluderende at &apos;fryse&apos; og udsmide beboere." name="Parcel Access">
- <action description="Administrér adgangsregler for parceller" longdescription="Administrér adgangsregler for parceller i &apos;Om land&apos; &gt; &apos;Adgang&apos; fanen." name="land manage allowed"/>
- <action description="Administrér liste med blokerede beboere på parceller" longdescription="Administrér liste med blokerede beboere på parceller i &apos;Om land&apos; &gt; &apos;Adgang&apos; fanen." name="land manage banned"/>
- <action description="Ændre indstillinger for at &apos;Sælge adgang til&apos; parceller" longdescription="Ændre indstillinger for at &apos;Sælge adgang til&apos; parceller i &apos;Om land&apos; &gt; &apos;Adgang&apos; fanen." name="land manage passes"/>
- <action description="Adgang til at smide beboere ud og &apos;fryse&apos; beboere på parceller" longdescription="Medlemmer med denne rolle kan håndtere beboere som ikke er velkomne på gruppe-ejet parceller ved at højreklikke på dem, vælge Mere&gt;, og vælge &apos;Smid ud...&apos; eller &apos;Frys...&apos;." name="land admin"/>
+ <action description="Administrér adgangsregler for parceller" longdescription="Administrér adgangsregler for parceller i &apos;Om land&apos; &gt; &apos;Adgang&apos; fanen." name="land manage allowed" value="29"/>
+ <action description="Administrér liste med blokerede beboere på parceller" longdescription="Administrér liste med blokerede beboere på parceller i &apos;Om land&apos; &gt; &apos;Adgang&apos; fanen." name="land manage banned" value="30"/>
+ <action description="Ændre indstillinger for at &apos;Sælge adgang til&apos; parceller" longdescription="Ændre indstillinger for at &apos;Sælge adgang til&apos; parceller i &apos;Om land&apos; &gt; &apos;Adgang&apos; fanen." name="land manage passes" value="31"/>
+ <action description="Adgang til at smide beboere ud og &apos;fryse&apos; beboere på parceller" longdescription="Medlemmer med denne rolle kan håndtere beboere som ikke er velkomne på gruppe-ejet parceller ved at højreklikke på dem, vælge Mere&gt;, og vælge &apos;Smid ud...&apos; eller &apos;Frys...&apos;." name="land admin" value="32"/>
</action_set>
<action_set description="Disse rettigheder inkluderer mulighed til at tillade beboere at returnere objekter og placere og flytte Linden planter. Dette er brugbart for at medlemmer kan holde orden og tilpasse landskabet. Denne mulighed skal benyttes med varsomhed, da der ikke er mulighed for at fortryde returnering af objekter og ændringer i landskabet." name="Parcel Content">
- <action description="Returnere objekter ejet af gruppen" longdescription="Returne objekter på gruppe-ejede parceller der er ejet af gruppen. Dette håndteres i &apos;Om land...&apos;&gt; &apos;Objekter&apos; fanen." name="land return group owned"/>
- <action description="Returnere objekter der er sat til &apos;gruppe&apos;" longdescription="Returnere objekter på gruppe-ejede parceller, der er &apos;sat til gruppe&apos; i &apos;Om land...&apos;&gt; &apos;Objekter&apos; fanen." name="land return group set"/>
- <action description="Returnere objekter der ikke er ejet af andre" longdescription="Returnere objekter på gruppe-ejede parceller, der er &apos;Ejet af andre&apos; i &apos;Om land...&apos;&gt; &apos;Objekter&apos; fanen." name="land return non group"/>
- <action description="Ændre landskab med Linden planter" longdescription="Disse rettigheder inkluderer mulighed til at tillade beboere at returnere objekter og placere og flytte Linden planter. Dette er brugbart for at medlemmer kan holde orden og tilpasse landskabet. Denne mulighed skal benyttes med varsomhed, da der ikke er mulighed for at fortryde returnering af objekter og ændringer i landskabet." name="land gardening"/>
+ <action description="Returnere objekter ejet af gruppen" longdescription="Returne objekter på gruppe-ejede parceller der er ejet af gruppen. Dette håndteres i &apos;Om land...&apos;&gt; &apos;Objekter&apos; fanen." name="land return group owned" value="48"/>
+ <action description="Returnere objekter der er sat til &apos;gruppe&apos;" longdescription="Returnere objekter på gruppe-ejede parceller, der er &apos;sat til gruppe&apos; i &apos;Om land...&apos;&gt; &apos;Objekter&apos; fanen." name="land return group set" value="33"/>
+ <action description="Returnere objekter der ikke er ejet af andre" longdescription="Returnere objekter på gruppe-ejede parceller, der er &apos;Ejet af andre&apos; i &apos;Om land...&apos;&gt; &apos;Objekter&apos; fanen." name="land return non group" value="34"/>
+ <action description="Ændre landskab med Linden planter" longdescription="Disse rettigheder inkluderer mulighed til at tillade beboere at returnere objekter og placere og flytte Linden planter. Dette er brugbart for at medlemmer kan holde orden og tilpasse landskabet. Denne mulighed skal benyttes med varsomhed, da der ikke er mulighed for at fortryde returnering af objekter og ændringer i landskabet." name="land gardening" value="35"/>
</action_set>
<action_set description="Disse rettigheder inkluderer mulighed til at dedikere, ændre og sælge gruppe-ejede objekter. Disse ændringer sker i &apos;Rediger&apos;&gt; &apos;Generelt&apos; fanen." name="Object Management">
- <action description="Dediker objekter til gruppe" longdescription="Dediker objekter til gruppe i &apos;Rediger&apos;&gt; &apos;Generelt&apos; fanen." name="object deed"/>
- <action description="Manipulér (flyt, kopiér, ændre) gruppe-ejede objekter" longdescription="Manipulér (flyt, kopiér, ændre) gruppe-ejede objekter i &apos;Rediger&apos;&gt; &apos;Generelt&apos; fanen." name="object manipulate"/>
- <action description="Sæt gruppe-ejede objekter til salg" longdescription="Sæt gruppe-ejede objekter til salg i &apos;Rediger&apos;&gt; &apos;Generelt&apos; fanen." name="object set sale"/>
+ <action description="Dediker objekter til gruppe" longdescription="Dediker objekter til gruppe i &apos;Rediger&apos;&gt; &apos;Generelt&apos; fanen." name="object deed" value="36"/>
+ <action description="Manipulér (flyt, kopiér, ændre) gruppe-ejede objekter" longdescription="Manipulér (flyt, kopiér, ændre) gruppe-ejede objekter i &apos;Rediger&apos;&gt; &apos;Generelt&apos; fanen." name="object manipulate" value="38"/>
+ <action description="Sæt gruppe-ejede objekter til salg" longdescription="Sæt gruppe-ejede objekter til salg i &apos;Rediger&apos;&gt; &apos;Generelt&apos; fanen." name="object set sale" value="39"/>
</action_set>
<action_set description="Disse rettigheder inkluderer mulighed til at håndtere betalinger for gruppen og styre adgang til gruppens kontobevægelser." name="Accounting">
- <action description="Betale gruppe regninger og modtage gruppe udbytte" longdescription="Medlemmer med denne rolle vil automatisk betale gruppe regninger og modtage gruppe udbytte. Det betyder at de vil modtager en andel af indtægter fra salg af gruppe-ejet land og bidrage til betaling af gruppe-relaterede betalinger, som f.eks. betaling for at paceller vises i lister. " name="accounting accountable"/>
+ <action description="Betale gruppe regninger og modtage gruppe udbytte" longdescription="Medlemmer med denne rolle vil automatisk betale gruppe regninger og modtage gruppe udbytte. Det betyder at de vil modtager en andel af indtægter fra salg af gruppe-ejet land og bidrage til betaling af gruppe-relaterede betalinger, som f.eks. betaling for at paceller vises i lister. " name="accounting accountable" value="40"/>
</action_set>
<action_set description="Disse rettigheder inkluderer adgang til at kunne sende, modtage og se gruppe beskeder." name="Notices">
- <action description="Send beskeder" longdescription="Medlemmer med denne rolle kan sende beskeder i &apos;Beskeder&apos; fanen." name="notices send"/>
- <action description="Modtage og se tidligere beskeder" longdescription="Medlemmer med denne rolle kan modtage og se tidligere beskeder i &apos;Beskeder&apos; fanen." name="notices receive"/>
- </action_set>
- <action_set description="Disse rettigheder inkluderer adgang til at kunne oprette forslag, stemme på forslag og se historik med forslag." name="Proposals">
- <action description="Opret forslag" longdescription="Medlemmer med denne rolle kan oprette forslag som der kan stemmes om i &apos;Forslag&apos; fanen." name="proposal start"/>
- <action description="Stem på forslag" longdescription="Medlemmer med denne rolle kan stemme på forslag i &apos;Forslag&apos; fanen." name="proposal vote"/>
+ <action description="Send beskeder" longdescription="Medlemmer med denne rolle kan sende beskeder i &apos;Beskeder&apos; fanen." name="notices send" value="42"/>
+ <action description="Modtage og se tidligere beskeder" longdescription="Medlemmer med denne rolle kan modtage og se tidligere beskeder i &apos;Beskeder&apos; fanen." name="notices receive" value="43"/>
</action_set>
<action_set description="Disse rettigheder styrer hvem der kan deltage i gruppe-chat og gruppe stemme-chat." name="Chat">
- <action description="Deltage i gruppe-chat" longdescription="Medlemmer med denne rolle kan deltage i gruppe-chat sessioner" name="join group chat"/>
- <action description="Deltag i gruppe stemme-chat" longdescription="Medlemmer med denne rolle kan deltage i gruppe stemme-chat sessioner. BEMÆRK: Medlemmet skal også have rollen &apos;Deltage i gruppe-chat&apos; for at denne rolle har effekt." name="join voice chat"/>
- <action description="Styr gruppe-chat" longdescription="Medlemmer med denne rolle kan kontrollere adgang og deltagelse i gruppe-chat og gruppe stemme-chat sessioner." name="moderate group chat"/>
+ <action description="Deltage i gruppe-chat" longdescription="Medlemmer med denne rolle kan deltage i gruppe-chat sessioner" name="join group chat" value="16"/>
+ <action description="Deltag i gruppe stemme-chat" longdescription="Medlemmer med denne rolle kan deltage i gruppe stemme-chat sessioner. BEMÆRK: Medlemmet skal også have rollen &apos;Deltage i gruppe-chat&apos; for at denne rolle har effekt." name="join voice chat" value="27"/>
+ <action description="Styr gruppe-chat" longdescription="Medlemmer med denne rolle kan kontrollere adgang og deltagelse i gruppe-chat og gruppe stemme-chat sessioner." name="moderate group chat" value="37"/>
</action_set>
</role_actions>
diff --git a/indra/newview/skins/default/xui/da/strings.xml b/indra/newview/skins/default/xui/da/strings.xml
index 1c583f2e95..198d8eea0e 100644
--- a/indra/newview/skins/default/xui/da/strings.xml
+++ b/indra/newview/skins/default/xui/da/strings.xml
@@ -191,6 +191,9 @@
<string name="TooltipAgentUrl">
Klik for at se beboers profil
</string>
+ <string name="TooltipAgentInspect">
+ Lær mere om denne beboer
+ </string>
<string name="TooltipAgentMute">
Klik for at slukke for denne beboer
</string>
@@ -738,6 +741,12 @@
<string name="Estate / Full Region">
Estate / Hel region
</string>
+ <string name="Estate / Homestead">
+ Estate / Homestead
+ </string>
+ <string name="Mainland / Homestead">
+ Mainland / Homestead
+ </string>
<string name="Mainland / Full Region">
Mainland / Hel region
</string>
@@ -3469,7 +3478,7 @@ Hvis du bliver ved med at modtage denne besked, kontakt venligst [SUPPORT_SITE].
Du er den eneste deltager i denne samtale
</string>
<string name="offline_message">
- [NAME] er ikke logget på.
+ [NAME] er logget af.
</string>
<string name="invite_message">
Tryk på [BUTTON NAME] knappen for at acceptére/tilslutte til denne stemme chat.
@@ -3538,7 +3547,10 @@ Hvis du bliver ved med at modtage denne besked, kontakt venligst [SUPPORT_SITE].
http://secondlife.com/landing/voicemorphing
</string>
<string name="paid_you_ldollars">
- [NAME] betalte dig L$[AMOUNT]
+ [NAME] betalte dig L$[AMOUNT] [REASON].
+ </string>
+ <string name="paid_you_ldollars_no_reason">
+ [NAME] betalte dig L$[AMOUNT].
</string>
<string name="you_paid_ldollars">
Du betalte [NAME] L$[AMOUNT] [REASON].
@@ -3552,6 +3564,9 @@ Hvis du bliver ved med at modtage denne besked, kontakt venligst [SUPPORT_SITE].
<string name="you_paid_ldollars_no_name">
Du betalte L$[AMOUNT] [REASON].
</string>
+ <string name="for item">
+ til [ITEM]
+ </string>
<string name="for a parcel of land">
for en parcel land
</string>
@@ -3570,6 +3585,9 @@ Hvis du bliver ved med at modtage denne besked, kontakt venligst [SUPPORT_SITE].
<string name="to upload">
for at uploade
</string>
+ <string name="to publish a classified ad">
+ til offentliggørelse af annonce
+ </string>
<string name="giving">
Giver L$ [AMOUNT]
</string>
diff --git a/indra/newview/skins/default/xui/de/panel_places.xml b/indra/newview/skins/default/xui/de/panel_places.xml
index 0e85829a0b..36c77d4fe1 100644
--- a/indra/newview/skins/default/xui/de/panel_places.xml
+++ b/indra/newview/skins/default/xui/de/panel_places.xml
@@ -21,7 +21,7 @@
<button label="Bearbeiten" name="edit_btn" tool_tip="Landmarken-Info bearbeiten"/>
</layout_panel>
<layout_panel name="overflow_btn_lp">
- <button label="▼" name="overflow_btn" tool_tip="Zusätzliche Optionen anzeigen"/>
+ <menu_button label="▼" name="overflow_btn" tool_tip="Zusätzliche Optionen anzeigen"/>
</layout_panel>
</layout_stack>
<layout_stack name="bottom_bar_ls3">
diff --git a/indra/newview/skins/default/xui/de/panel_profile.xml b/indra/newview/skins/default/xui/de/panel_profile.xml
index 40fa2f922a..938631f65d 100644
--- a/indra/newview/skins/default/xui/de/panel_profile.xml
+++ b/indra/newview/skins/default/xui/de/panel_profile.xml
@@ -57,7 +57,7 @@
<button label="Teleportieren" name="teleport" tool_tip="Teleport anbieten"/>
</layout_panel>
<layout_panel name="overflow_btn_lp">
- <button label="▼" name="overflow_btn" tool_tip="Dem Einwohner Geld geben oder Inventar an den Einwohner schicken"/>
+ <menu_button label="▼" name="overflow_btn" tool_tip="Dem Einwohner Geld geben oder Inventar an den Einwohner schicken"/>
</layout_panel>
</layout_stack>
</layout_panel>
diff --git a/indra/newview/skins/default/xui/en/floater_buy_currency.xml b/indra/newview/skins/default/xui/en/floater_buy_currency.xml
index cd5922a9a2..49deb9b025 100644
--- a/indra/newview/skins/default/xui/en/floater_buy_currency.xml
+++ b/indra/newview/skins/default/xui/en/floater_buy_currency.xml
@@ -20,6 +20,7 @@
left="0"
name="normal_background"
top="17"
+ use_draw_context_alpha="false"
width="350" />
<text
type="string"
@@ -292,6 +293,7 @@ Re-enter amount to see the latest exchange rate.
left="0"
name="error_background"
top="15"
+ use_draw_context_alpha="false"
width="350"/>
<text
type="string"
diff --git a/indra/newview/skins/default/xui/en/floater_nearby_chat.xml b/indra/newview/skins/default/xui/en/floater_nearby_chat.xml
index 4c5113aa55..ab966dbb0e 100644
--- a/indra/newview/skins/default/xui/en/floater_nearby_chat.xml
+++ b/indra/newview/skins/default/xui/en/floater_nearby_chat.xml
@@ -2,9 +2,6 @@
<floater
border_visible="false"
border="false"
- bg_opaque_image="Window_Foreground"
- bg_alpha_image="Window_Background"
- bg_alpha_image_overlay="DkGray_66"
legacy_header_height="18"
can_minimize="true"
can_tear_off="false"
diff --git a/indra/newview/skins/default/xui/en/floater_preferences.xml b/indra/newview/skins/default/xui/en/floater_preferences.xml
index 36108442f3..8eee8f44b5 100644
--- a/indra/newview/skins/default/xui/en/floater_preferences.xml
+++ b/indra/newview/skins/default/xui/en/floater_preferences.xml
@@ -83,7 +83,7 @@
label="Move &amp; View"
layout="topleft"
help_topic="preferences_move_tab"
- name="audio" />
+ name="move" />
<panel
class="panel_preference"
filename="panel_preferences_alerts.xml"
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index f361cb7f8e..e70e1eb61b 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -160,7 +160,7 @@
layout="topleft"
left="10"
height="70"
- top="54"
+ top="59"
name="focus_radio_group">
<radio_item
top_pad="6"
@@ -197,7 +197,7 @@
<radio_group
left="10"
height="70"
- top="54"
+ top="59"
layout="topleft"
name="move_radio_group">
<radio_item
@@ -931,7 +931,7 @@
height="23"
image_overlay="Edit_Wrench"
layout="topleft"
- left_pad="3"
+ left_pad="13"
name="button set group"
tab_stop="false"
tool_tip="Choose a group to share this object's permissions"
@@ -944,7 +944,7 @@
name="checkbox share with group"
tool_tip="Allow all members of the set group to share your modify permissions for this object. You must Deed to enable role restrictions."
top_pad="10"
- left="106"
+ left="100"
width="87" />
<button
follows="top|left"
@@ -953,7 +953,7 @@
label_selected="Deed"
layout="topleft"
name="button deed"
- left_pad="3"
+ left_pad="19"
tool_tip="Deeding gives this item away with next owner permissions. Group shared objects can be deeded by a group officer."
width="80" />
<text
@@ -974,7 +974,7 @@
layout="topleft"
name="clickaction"
width="148"
- left_pad="0">
+ left_pad="10">
<combo_box.item
label="Touch (default)"
name="Touch/grab(default)"
@@ -1009,7 +1009,7 @@
width="100" />
<!-- NEW SALE TYPE COMBO BOX -->
<combo_box
- left_pad="0"
+ left_pad="10"
layout="topleft"
follows="left|top"
allow_text_entry="false"
@@ -1041,7 +1041,7 @@ even though the user gets a free copy.
decimal_digits="0"
increment="1"
top_pad="8"
- left="108"
+ left="118"
control_name="Edit Cost"
name="Edit Cost"
label="Price: L$"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index f74b6ba7b5..907f68dc06 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -94,6 +94,49 @@
function="Floater.Toggle"
parameter="voice_effect" />
</menu_item_check>
+ <menu
+ create_jump_keys="true"
+ label="Movement"
+ name="Movement"
+ tear_off="true">
+ <menu_item_call
+ label="Sit Down"
+ layout="topleft"
+ shortcut="alt|shift|S"
+ name="Sit Down Here">
+ <menu_item_call.on_click
+ function="Self.SitDown"
+ parameter="" />
+ <menu_item_call.on_enable
+ function="Self.EnableSitDown" />
+ </menu_item_call>
+ <menu_item_check
+ label="Fly"
+ name="Fly"
+ shortcut="Home">
+ <menu_item_check.on_check
+ function="Agent.getFlying" />
+ <menu_item_check.on_click
+ function="Agent.toggleFlying" />
+ <menu_item_check.on_enable
+ function="Agent.enableFlying" />
+ </menu_item_check>
+ <menu_item_check
+ label="Always Run"
+ name="Always Run"
+ shortcut="control|R">
+ <menu_item_check.on_check
+ function="World.CheckAlwaysRun" />
+ <menu_item_check.on_click
+ function="World.AlwaysRun" />
+ </menu_item_check>
+ <menu_item_call
+ label="Stop Animating Me"
+ name="Stop Animating My Avatar">
+ <menu_item_call.on_click
+ function="Tools.StopAllAnimations" />
+ </menu_item_call>
+ </menu>
<menu
create_jump_keys="true"
label="My Status"
@@ -947,6 +990,14 @@
function="ShowHelp"
parameter="f1_help" />
</menu_item_call>
+ <menu_item_check
+ label="Enable Hints"
+ name="Enable Hints">
+ <on_check
+ control="EnableUIHints"/>
+ <on_click
+ function="ToggleUIHints"/>
+ </menu_item_check>
<!-- <menu_item_call
label="Tutorial"
name="Tutorial">
@@ -980,14 +1031,6 @@
function="Floater.Show"
parameter="sl_about" />
</menu_item_call>
- <menu_item_check
- label="Enable Hints"
- name="Enable Hints">
- <on_check
- control="EnableUIHints"/>
- <on_click
- function="ToggleUIHints"/>
- </menu_item_check>
</menu>
<menu
create_jump_keys="true"
@@ -996,12 +1039,6 @@
tear_off="true"
visible="false">
<menu_item_call
- label="Stop Animating Me"
- name="Stop Animating My Avatar">
- <menu_item_call.on_click
- function="Tools.StopAllAnimations" />
- </menu_item_call>
- <menu_item_call
label="Rebake Textures"
name="Rebake Texture"
shortcut="control|alt|R">
@@ -1553,29 +1590,6 @@
<menu_item_separator/>
- <menu_item_check
- label="Always Run"
- name="Always Run"
- shortcut="control|R">
- <menu_item_check.on_check
- function="World.CheckAlwaysRun" />
- <menu_item_check.on_click
- function="World.AlwaysRun" />
- </menu_item_check>
- <menu_item_check
- label="Fly"
- name="Fly"
- shortcut="Home">
- <menu_item_check.on_check
- function="Agent.getFlying" />
- <menu_item_check.on_click
- function="Agent.toggleFlying" />
- <menu_item_check.on_enable
- function="Agent.enableFlying" />
- </menu_item_check>
-
- <menu_item_separator/>
-
<menu_item_call
label="Close Window"
name="Close Window"
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 1247e4724e..60b876d163 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -909,6 +909,13 @@ The new skin will appear after you restart [APP_NAME].
<notification
icon="alertmodal.tga"
+ name="ChangeLanguage"
+ type="alertmodal">
+Changing language will take effect after you restart [APP_NAME].
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
name="GoToAuctionPage"
type="alertmodal">
Go to the [SECOND_LIFE] web page to see auction details or make a bid?
@@ -2871,6 +2878,25 @@ Download to your Applications folder?
<notification
icon="alertmodal.tga"
+ name="FailedUpdateInstall"
+ type="alertmodal">
+An error occurred installing the viewer update.
+Please download and install the latest viewer from
+http://secondlife.com/download.
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+ <notification
+ icon="notifytip.tga"
+ name="DownloadBackground"
+ type="notifytip">
+An updated version of [APP_NAME] has been downloaded.
+It will be applied the next time you restart [APP_NAME]
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
name="DeedObjectToGroup"
type="alertmodal">
Deeding this object will cause the group to:
diff --git a/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
index 6f3629cc8f..4b21ffa1f9 100644
--- a/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
+++ b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
@@ -62,7 +62,7 @@
name="avatar_name"
top="6"
use_ellipses="true"
- value="Unknown"
+ value="(loading)"
width="180" />
<text
follows="right"
diff --git a/indra/newview/skins/default/xui/en/panel_classified_info.xml b/indra/newview/skins/default/xui/en/panel_classified_info.xml
index 0fb7691ee7..6c8d994bc6 100644
--- a/indra/newview/skins/default/xui/en/panel_classified_info.xml
+++ b/indra/newview/skins/default/xui/en/panel_classified_info.xml
@@ -49,7 +49,8 @@
left="10"
tab_stop="false"
top="2"
- width="30" />
+ width="30"
+ use_draw_context_alpha="false" />
<text
follows="top|left|right"
font="SansSerifHugeBold"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_alpha.xml b/indra/newview/skins/default/xui/en/panel_edit_alpha.xml
index 7bcd4962d2..813aa5d7a9 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_alpha.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_alpha.xml
@@ -8,6 +8,17 @@
name="edit_alpha_panel"
top_pad="10"
width="333" >
+ <scroll_container
+ color="DkGray2"
+ follows="all"
+ height="400"
+ layout="topleft"
+ left="10"
+ top_pad="0"
+ name="avatar_alpha_color_panel_scroll"
+ reserve_scroll_corner="false"
+ opaque="true"
+ width="313">
<panel
border="false"
bg_alpha_color="DkGray2"
@@ -16,14 +27,14 @@
background_opaque="true"
follows="top|left|right"
height="400"
- left="10"
+ left="0"
layout="topleft"
name="avatar_alpha_color_panel"
top="0"
width="313" >
<check_box
control_name="LowerAlphaTextureInvisible"
- follows="left"
+ follows="left|top"
height="16"
layout="topleft"
left="5"
@@ -48,7 +59,7 @@
<check_box
control_name="UpperAlphaTextureInvisible"
- follows="left"
+ follows="left|top"
height="16"
layout="topleft"
left_pad="20"
@@ -73,7 +84,7 @@
<check_box
control_name="HeadAlphaTextureInvisible"
- follows="left"
+ follows="left|top"
height="16"
layout="topleft"
left="5"
@@ -98,7 +109,7 @@
<check_box
control_name="Eye AlphaTextureInvisible"
- follows="left"
+ follows="left|top"
height="16"
layout="topleft"
left_pad="20"
@@ -123,7 +134,7 @@
<check_box
control_name="HairAlphaTextureInvisible"
- follows="left"
+ follows="left|top"
height="16"
layout="topleft"
left="5"
@@ -147,5 +158,6 @@
</texture_picker>
</panel>
+ </scroll_container>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_edit_classified.xml b/indra/newview/skins/default/xui/en/panel_edit_classified.xml
index f60c1e62ac..e512d63f9e 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_classified.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_classified.xml
@@ -33,7 +33,8 @@
left="10"
tab_stop="false"
top="2"
- width="30" />
+ width="30"
+ use_draw_context_alpha="false" />
<text
type="string"
length="1"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_pick.xml b/indra/newview/skins/default/xui/en/panel_edit_pick.xml
index a284d3ccc0..a028e3ab9f 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_pick.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_pick.xml
@@ -27,7 +27,8 @@
left="10"
tab_stop="false"
top="2"
- width="30" />
+ width="30"
+ use_draw_context_alpha="false" />
<text
type="string"
length="1"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml
index 23a08344ea..97f1a1a658 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml
@@ -14,7 +14,7 @@
bg_opaque_color="DkGray2"
background_visible="true"
background_opaque="true"
- follows="top|left|right"
+ follows="all"
height="400"
left="10"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_wearable.xml b/indra/newview/skins/default/xui/en/panel_edit_wearable.xml
index b3e9586ee9..ac8917d272 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_wearable.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_wearable.xml
@@ -147,7 +147,8 @@
pad_left="24"
tool_tip="Return to Edit Outfit"
top="3"
- width="30" />
+ width="30"
+ use_draw_context_alpha="false" />
<text
follows="top|left|right"
font="SansSerifHugeBold"
diff --git a/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml b/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml
index 0347d2feec..ec3f3b48bc 100644
--- a/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml
@@ -45,7 +45,8 @@ background_visible="true"
left="7"
tab_stop="false"
top="2"
- width="30" />
+ width="30"
+ use_draw_context_alpha="false" />
<text_editor
allow_scroll="false"
bg_visible="false"
diff --git a/indra/newview/skins/default/xui/en/panel_landmark_info.xml b/indra/newview/skins/default/xui/en/panel_landmark_info.xml
index 6ee2abc70f..d2088594dd 100644
--- a/indra/newview/skins/default/xui/en/panel_landmark_info.xml
+++ b/indra/newview/skins/default/xui/en/panel_landmark_info.xml
@@ -68,7 +68,8 @@
tool_tip="Back"
tab_stop="false"
top="4"
- width="30" />
+ width="30"
+ use_draw_context_alpha="false" />
<text
follows="top|left|right"
font="SansSerifHugeBold"
diff --git a/indra/newview/skins/default/xui/en/panel_landmarks.xml b/indra/newview/skins/default/xui/en/panel_landmarks.xml
index 2a5933e3e9..23d8cb11ca 100644
--- a/indra/newview/skins/default/xui/en/panel_landmarks.xml
+++ b/indra/newview/skins/default/xui/en/panel_landmarks.xml
@@ -114,6 +114,7 @@
height="25"
layout="topleft"
name="options_gear_btn_panel"
+ user_resize="false"
width="32">
<menu_button
follows="bottom|left"
@@ -134,6 +135,7 @@
height="25"
layout="topleft"
name="add_btn_panel"
+ user_resize="false"
width="32">
<button
follows="bottom|left"
@@ -154,6 +156,7 @@
height="25"
layout="topleft"
name="dummy_panel"
+ user_resize="false"
width="212">
<icon
follows="bottom|left|right"
@@ -170,6 +173,7 @@
height="25"
layout="topleft"
name="trash_btn_panel"
+ user_resize="false"
width="31">
<dnd_button
follows="bottom|left"
diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
index 2b6e082542..96633cb5b4 100644
--- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
@@ -118,6 +118,7 @@
height="25"
layout="topleft"
name="options_gear_btn_panel"
+ user_resize="false"
width="32">
<menu_button
follows="bottom|left"
@@ -138,6 +139,7 @@
height="25"
layout="topleft"
name="add_btn_panel"
+ user_resize="false"
width="32">
<button
follows="bottom|left"
@@ -158,6 +160,7 @@
height="25"
layout="topleft"
name="dummy_panel"
+ user_resize="false"
width="212">
<icon
follows="bottom|left|right"
@@ -174,6 +177,7 @@
height="25"
layout="topleft"
name="trash_btn_panel"
+ user_resize="false"
width="31">
<dnd_button
follows="bottom|left"
diff --git a/indra/newview/skins/default/xui/en/panel_notify_textbox.xml b/indra/newview/skins/default/xui/en/panel_notify_textbox.xml
new file mode 100644
index 0000000000..4634eeed46
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_notify_textbox.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ background_visible="true"
+ height="230"
+ label="instant_message"
+ layout="topleft"
+ left="0"
+ name="panel_notify_textbox"
+ top="0"
+ width="305">
+ <string
+ name="message_max_lines_count"
+ value="7" />
+ <panel
+ bevel_style="none"
+ follows="left|right|top"
+ height="150"
+ label="info_panel"
+ layout="topleft"
+ left="0"
+ name="info_panel"
+ top="0"
+ width="305">
+ <text_editor
+ parse_urls="true"
+ enabled="true"
+ follows="all"
+ height="60"
+ layout="topleft"
+ left="25"
+ max_length="250"
+ name="message"
+ parse_highlights="true"
+ read_only="false"
+ top="40"
+ type="string"
+ use_ellipses="true"
+ value="message"
+ width="260"
+ word_wrap="true" >
+ </text_editor>
+ parse_urls="false"
+ <button
+ top="110"
+ follows="top|left"
+ height="20"
+ label="Submit"
+ layout="topleft"
+ left="25"
+ name="btn_submit"
+ width="70" />
+ </panel>
+ <panel
+ background_visible="false"
+ follows="left|right|bottom"
+ height="0"
+ width="290"
+ label="control_panel"
+ layout="topleft"
+ left="10"
+ name="control_panel"
+ top_pad="5">
+ <!--
+ Notes:
+ This panel holds the Ignore button and possibly other buttons of notification.
+ -->
+ </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml
index f4dee9cd55..e1cd78bad8 100644
--- a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml
+++ b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml
@@ -70,7 +70,8 @@
left="5"
tab_stop="false"
top="1"
- width="30" />
+ width="30"
+ use_draw_context_alpha="false" />
<text
follows="top|left|right"
font="SansSerifHugeBold"
diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml
index 68c423d7dd..6a8bf87bc5 100644
--- a/indra/newview/skins/default/xui/en/panel_people.xml
+++ b/indra/newview/skins/default/xui/en/panel_people.xml
@@ -241,6 +241,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
height="25"
layout="topleft"
name="options_gear_btn_panel"
+ user_resize="false"
width="32">
<menu_button
follows="bottom|left"
@@ -261,6 +262,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
height="25"
layout="topleft"
name="add_btn_panel"
+ user_resize="false"
width="32">
<button
follows="bottom|left"
@@ -281,6 +283,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
height="25"
layout="topleft"
name="dummy_panel"
+ user_resize="false"
width="212">
<icon
follows="bottom|left|right"
@@ -297,6 +300,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
height="25"
layout="topleft"
name="trash_btn_panel"
+ user_resize="false"
width="31">
<dnd_button
follows="bottom|left"
diff --git a/indra/newview/skins/default/xui/en/panel_pick_info.xml b/indra/newview/skins/default/xui/en/panel_pick_info.xml
index 0496c86215..7daa52b2d9 100644
--- a/indra/newview/skins/default/xui/en/panel_pick_info.xml
+++ b/indra/newview/skins/default/xui/en/panel_pick_info.xml
@@ -21,7 +21,8 @@
left="10"
tab_stop="false"
top="2"
- width="30" />
+ width="30"
+ use_draw_context_alpha="false" />
<text
follows="top|left|right"
font="SansSerifHugeBold"
diff --git a/indra/newview/skins/default/xui/en/panel_place_profile.xml b/indra/newview/skins/default/xui/en/panel_place_profile.xml
index 8036411d2b..7e89860c60 100644
--- a/indra/newview/skins/default/xui/en/panel_place_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_place_profile.xml
@@ -165,7 +165,8 @@
tool_tip="Back"
tab_stop="false"
top="4"
- width="30" />
+ width="30"
+ use_draw_context_alpha="false" />
<text
follows="top|left|right"
font="SansSerifHugeBold"
diff --git a/indra/newview/skins/default/xui/en/panel_places.xml b/indra/newview/skins/default/xui/en/panel_places.xml
index 21314703b0..d9c357f277 100644
--- a/indra/newview/skins/default/xui/en/panel_places.xml
+++ b/indra/newview/skins/default/xui/en/panel_places.xml
@@ -211,7 +211,7 @@ background_visible="true"
user_resize="false"
auto_resize="true"
width="24">
- <button
+ <menu_button
follows="bottom|left|right"
height="23"
label="▼"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_colors.xml b/indra/newview/skins/default/xui/en/panel_preferences_colors.xml
index 6dc419a96c..5797a63f4e 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_colors.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_colors.xml
@@ -275,14 +275,14 @@
height="12"
name="bubble_chat"
top_pad="20"
- width="120"
+ width="140"
>
- Bubble chat:
+ Bubble chat background:
</text>
<color_swatch
can_apply_immediately="true"
color="0 0 0 1"
- control_name="BackgroundChatColor"
+ control_name="NameTagBackground"
follows="left|top"
height="24"
label_height="0"
@@ -294,10 +294,10 @@
width="44">
<color_swatch.init_callback
function="Pref.getUIColor"
- parameter="BackgroundChatColor" />
+ parameter="NameTagBackground" />
<color_swatch.commit_callback
function="Pref.applyUIColor"
- parameter="BackgroundChatColor" />
+ parameter="NameTagBackground" />
</color_swatch>
<slider
control_name="ChatBubbleOpacity"
@@ -317,7 +317,7 @@
layout="topleft"
left="30"
height="12"
- name="bubble_chat"
+ name="floater_opacity"
top_pad="15"
width="120"
>
@@ -333,7 +333,7 @@
initial_value="0.8"
layout="topleft"
label_width="115"
- label="Active :"
+ label="Active:"
left="50"
max_val="1.00"
min_val="0.00"
@@ -351,11 +351,11 @@
initial_value="0.5"
layout="topleft"
label_width="115"
- label="Inctive :"
+ label="Inactive:"
left="50"
max_val="1.00"
min_val="0.00"
- name="active"
+ name="inactive"
show_text="true"
top_pad="5"
width="415" />
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_general.xml b/indra/newview/skins/default/xui/en/panel_preferences_general.xml
index a660b5d785..36f8f99178 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_general.xml
@@ -331,6 +331,7 @@
Pressing letter keys:
</text>
<radio_group
+ control_name="LetterKeysFocusChatBar"
height="20"
layout="topleft"
left="35"
@@ -338,12 +339,12 @@
name="inworld_typing_preference">
<radio_item
label="Starts local chat"
- name="radio_button1"
+ name="radio_start_chat"
top_delta="20"
layout="topleft"
height="16"
left="0"
- value="0"
+ value="1"
width="150" />
<radio_item
label="Affects movement (i.e. WASD)"
@@ -351,8 +352,8 @@
layout="topleft"
top_delta="0"
height="16"
- name="radio_button2"
- value="1"
+ name="radio_move"
+ value="0"
width="75" />
</radio_group>
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
index 3ceee60927..6573822d1a 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
@@ -181,7 +181,7 @@
label="Transparent Water"
layout="topleft"
left_delta="0"
- name="BumpShiny"
+ name="TransparentWater"
top_pad="7"
width="256" />
<check_box
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
index 2ddb81559f..626122c0b0 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
@@ -185,7 +185,7 @@
layout="topleft"
left_pad="10"
mouse_opaque="false"
- name="cache_size_label_l"
+ name="block_list_label"
top_delta="3"
text_color="LtGray_50"
width="300">
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
index 14aa38c5d3..584bd1ea9d 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
@@ -341,4 +341,20 @@
name="web_proxy_port"
top_delta="0"
width="145" />
+
+ <check_box
+ top_delta="2"
+ enabled="true"
+ follows="left|top"
+ height="18"
+ initial_value="true"
+ control_name="UpdaterServiceActive"
+ label="Automatically download and install [APP_NAME] updates"
+ left="30"
+ mouse_opaque="true"
+ name="updater_service_active"
+ radio_style="false"
+ width="400"
+ top_pad="10"/>
+
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
index 8ade41f587..da366f30ae 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
@@ -70,7 +70,7 @@
name="UI Volume"
show_text="false"
slider_label.halign="right"
- top_pad="5"
+ top_pad="4"
volume="true"
width="300">
<slider.commit_callback
@@ -104,7 +104,7 @@
name="Wind Volume"
show_text="false"
slider_label.halign="right"
- top_pad="5"
+ top_pad="4"
volume="true"
width="300">
<slider.commit_callback
@@ -138,7 +138,7 @@
left="0"
name="SFX Volume"
show_text="false"
- top_pad="7"
+ top_pad="4"
volume="true"
width="300">
<slider.commit_callback
@@ -172,7 +172,7 @@
name="Music Volume"
slider_label.halign="right"
show_text="false"
- top_pad="5"
+ top_pad="4"
volume="true"
width="300">
<slider.commit_callback
@@ -215,7 +215,7 @@
name="Media Volume"
show_text="false"
slider_label.halign="right"
- top_pad="5"
+ top_pad="4"
volume="true"
width="300">
<slider.commit_callback
@@ -257,7 +257,7 @@
label_width="120"
layout="topleft"
left="0"
- top_pad="5"
+ top_pad="4"
name="Voice Volume"
show_text="false"
slider_label.halign="right"
@@ -301,9 +301,9 @@
height="15"
tool_tip="Check this to let media auto-play if it wants"
label="Allow Media to auto-play"
- top_pad="5"
+ top_pad="1"
left="25"/>
- <check_box
+ <check_box
name="media_show_on_others_btn"
control_name="MediaShowOnOthers"
value="true"
@@ -313,16 +313,6 @@
label="Play media attached to other avatars"
left="25"
width="230"/>
- <check_box
- control_name="LipSyncEnabled"
- follows="left|top"
- height="20"
- label="Move avatar lips when speaking"
- layout="topleft"
- left_pad="0"
- name="enable_lip_sync"
- width="237"
- top_delta="-4" />
<text
type="string"
@@ -333,7 +323,7 @@
left="25"
name="voice_chat_settings"
width="180"
- top_pad="10">
+ top_pad="7">
Voice Chat Settings
</text>
<text
@@ -341,10 +331,10 @@
length="1"
follows="left|top"
layout="topleft"
- left="80"
+ left="46"
top_delta="16"
name="Listen from"
- width="102">
+ width="112">
Listen from:
</text>
<icon
@@ -363,7 +353,7 @@
height="18"
image_name="Move_Walk_Off"
layout="topleft"
- left_pad="130"
+ left_pad="170"
name="avatar_icon"
mouse_opaque="false"
visible="true"
@@ -375,7 +365,7 @@
draw_border="false"
follows="left|top"
layout="topleft"
- left_delta="-128"
+ left_delta="-168"
width="221"
height="20"
name="ear_location">
@@ -391,11 +381,21 @@
follows="left|top"
label="Avatar position"
layout="topleft"
- left_pad="-54"
+ left_pad="-16"
name="1"
top_delta ="0"
width="200" />
</radio_group>
+ <check_box
+ control_name="LipSyncEnabled"
+ follows="left|top"
+ height="15"
+ label="Move avatar lips when speaking"
+ layout="topleft"
+ left="44"
+ name="enable_lip_sync"
+ top_pad="5"
+ width="237"/>
<check_box
follows="top|left"
enabled_control="EnableVoiceChat"
@@ -403,10 +403,11 @@
height="15"
label="Toggle speak on/off when I press:"
layout="topleft"
- left="30"
+ left="44"
name="push_to_talk_toggle_check"
width="237"
- tool_tip="When in toggle mode, press and release the trigger key ONCE to switch your microphone on or off. When not in toggle mode, the microphone broadcasts your voice only while the trigger is being held down."/>
+ tool_tip="When in toggle mode, press and release the trigger key ONCE to switch your microphone on or off. When not in toggle mode, the microphone broadcasts your voice only while the trigger is being held down."
+ top_pad="3"/>
<line_editor
follows="top|left"
control_name="PushToTalkButton"
@@ -454,7 +455,7 @@
label="Input/Output devices"
layout="topleft"
left="20"
- top_pad="8"
+ top_pad="6"
name="device_settings_btn"
width="190">
</button>
diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml
index efc37c2127..7caf425058 100644
--- a/indra/newview/skins/default/xui/en/panel_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile.xml
@@ -432,7 +432,7 @@
user_resize="false"
auto_resize="false"
width="24">
- <button
+ <menu_button
follows="bottom|left|right"
height="23"
label="▼"
diff --git a/indra/newview/skins/default/xui/en/panel_profile_view.xml b/indra/newview/skins/default/xui/en/panel_profile_view.xml
index 97229c413c..c553a3aba0 100644
--- a/indra/newview/skins/default/xui/en/panel_profile_view.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile_view.xml
@@ -27,7 +27,8 @@
left="10"
tab_stop="false"
top="2"
- width="30" />
+ width="30"
+ use_draw_context_alpha="false" />
<text
top="10"
follows="top|left"
diff --git a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
index 6940d1549b..54a312bd59 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
@@ -56,7 +56,8 @@
name="back_btn"
tab_stop="false"
top="2"
- width="30" />
+ width="30"
+ use_draw_context_alpha="false" />
<text
follows="top|left|right"
font="SansSerifHugeBold"
diff --git a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
index ca63d2df39..afaf41d073 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
@@ -65,7 +65,8 @@
name="back_btn"
tab_stop="false"
top="0"
- width="30" />
+ width="30"
+ use_draw_context_alpha="false" />
<text
follows="top|left|right"
font="SansSerifHuge"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 1ec0d34d9a..51fba470cb 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -1823,8 +1823,8 @@ key llRequestUsername(key id)
Requests single-word username of an avatar. When data is available the dataserver event will be raised.
</string>
<string name="LSLTipText_llGetDisplayName" translate="false">
-string llGetDisplayName(key id)
-Returns the name of an avatar, iff the avatar is in the current simulator, otherwise the empty string.
+ string llGetDisplayName(key id)
+ Returns the name of an avatar, iff the avatar is in the current simulator, and the name has been cached, otherwise the same as llGetUsername. Use llRequestDisplayName if you absolutely must have the display name.
</string>
<string name="LSLTipText_llRequestDisplayName" translate="false">
key llRequestDisplayName(key id)
diff --git a/indra/newview/skins/default/xui/en/widgets/avatar_icon.xml b/indra/newview/skins/default/xui/en/widgets/avatar_icon.xml
index a35e2c3663..a1e32e44de 100644
--- a/indra/newview/skins/default/xui/en/widgets/avatar_icon.xml
+++ b/indra/newview/skins/default/xui/en/widgets/avatar_icon.xml
@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<avatar_icon default_icon_name="Generic_Person_Large">
+<avatar_icon
+ default_icon_name="Generic_Person_Large"
+ use_draw_context_alpha="false">
</avatar_icon>
diff --git a/indra/newview/skins/default/xui/en/widgets/button.xml b/indra/newview/skins/default/xui/en/widgets/button.xml
index 2d0a1728d5..1746a045cf 100644
--- a/indra/newview/skins/default/xui/en/widgets/button.xml
+++ b/indra/newview/skins/default/xui/en/widgets/button.xml
@@ -24,5 +24,6 @@
halign="center"
pad_bottom="3"
height="23"
- scale_image="true">
+ scale_image="true"
+ use_draw_context_alpha="true">
</button>
diff --git a/indra/newview/skins/default/xui/en/widgets/icon.xml b/indra/newview/skins/default/xui/en/widgets/icon.xml
index adb743a628..cf8edfcedb 100644
--- a/indra/newview/skins/default/xui/en/widgets/icon.xml
+++ b/indra/newview/skins/default/xui/en/widgets/icon.xml
@@ -3,5 +3,6 @@
tab_stop="false"
mouse_opaque="false"
name="icon"
+ use_draw_context_alpha="true"
follows="left|top">
</icon>
diff --git a/indra/newview/skins/default/xui/es/panel_places.xml b/indra/newview/skins/default/xui/es/panel_places.xml
index 2e349c7fe2..4c90a7e6b4 100644
--- a/indra/newview/skins/default/xui/es/panel_places.xml
+++ b/indra/newview/skins/default/xui/es/panel_places.xml
@@ -21,7 +21,7 @@
<button label="Editar" name="edit_btn" tool_tip="Editar la información del hito"/>
</layout_panel>
<layout_panel name="overflow_btn_lp">
- <button label="▼" name="overflow_btn" tool_tip="Ver más opciones"/>
+ <menu_button label="▼" name="overflow_btn" tool_tip="Ver más opciones"/>
</layout_panel>
</layout_stack>
<layout_stack name="bottom_bar_ls3">
diff --git a/indra/newview/skins/default/xui/es/panel_profile.xml b/indra/newview/skins/default/xui/es/panel_profile.xml
index 5cfe83cd61..339a1f236b 100644
--- a/indra/newview/skins/default/xui/es/panel_profile.xml
+++ b/indra/newview/skins/default/xui/es/panel_profile.xml
@@ -53,7 +53,7 @@
<button label="Teleporte" name="teleport" tool_tip="Ofrecer teleporte"/>
</layout_panel>
<layout_panel name="overflow_btn_lp">
- <button label="▼" name="overflow_btn" tool_tip="Pagar dinero al Residente o compartir algo del inventario con él"/>
+ <menu_button label="▼" name="overflow_btn" tool_tip="Pagar dinero al Residente o compartir algo del inventario con él"/>
</layout_panel>
</layout_stack>
</layout_panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_places.xml b/indra/newview/skins/default/xui/fr/panel_places.xml
index 7f3601b90d..e252c224f8 100644
--- a/indra/newview/skins/default/xui/fr/panel_places.xml
+++ b/indra/newview/skins/default/xui/fr/panel_places.xml
@@ -21,7 +21,7 @@
<button label="Modifier" name="edit_btn" tool_tip="Modifier les informations du repère"/>
</layout_panel>
<layout_panel name="overflow_btn_lp">
- <button label="▼" name="overflow_btn" tool_tip="Afficher d&apos;autres options"/>
+ <menu_button label="▼" name="overflow_btn" tool_tip="Afficher d&apos;autres options"/>
</layout_panel>
</layout_stack>
<layout_stack name="bottom_bar_ls3">
diff --git a/indra/newview/skins/default/xui/fr/panel_profile.xml b/indra/newview/skins/default/xui/fr/panel_profile.xml
index 4606f5a0c6..6b611923af 100644
--- a/indra/newview/skins/default/xui/fr/panel_profile.xml
+++ b/indra/newview/skins/default/xui/fr/panel_profile.xml
@@ -57,7 +57,7 @@
<button label="Téléporter" name="teleport" tool_tip="Proposer une téléportation"/>
</layout_panel>
<layout_panel name="overflow_btn_lp">
- <button label="▼" name="overflow_btn" tool_tip="Payer le résident ou partager l&apos;inventaire avec lui"/>
+ <menu_button label="▼" name="overflow_btn" tool_tip="Payer le résident ou partager l&apos;inventaire avec lui"/>
</layout_panel>
</layout_stack>
</layout_panel>
diff --git a/indra/newview/skins/default/xui/it/floater_tools.xml b/indra/newview/skins/default/xui/it/floater_tools.xml
index fbe611407e..a8c985cb12 100644
--- a/indra/newview/skins/default/xui/it/floater_tools.xml
+++ b/indra/newview/skins/default/xui/it/floater_tools.xml
@@ -283,7 +283,7 @@
<combo_box.item label="Plastica" name="Plastic"/>
<combo_box.item label="Gomma" name="Rubber"/>
</combo_box>
- <text name="text cut">
+ <text name="text cut" left_delta="-10" width="170">
Riduci una sezione (inizio/fine)
</text>
<spinner label="I" name="cut begin"/>
diff --git a/indra/newview/skins/default/xui/it/panel_places.xml b/indra/newview/skins/default/xui/it/panel_places.xml
index e33f8190eb..61830f186f 100644
--- a/indra/newview/skins/default/xui/it/panel_places.xml
+++ b/indra/newview/skins/default/xui/it/panel_places.xml
@@ -21,7 +21,7 @@
<button label="Modifica" name="edit_btn" tool_tip="Modifica le informazioni del punto di riferimento"/>
</layout_panel>
<layout_panel name="overflow_btn_lp">
- <button label="▼" name="overflow_btn" tool_tip="Mostra ulteriori opzioni"/>
+ <menu_button label="▼" name="overflow_btn" tool_tip="Mostra ulteriori opzioni"/>
</layout_panel>
</layout_stack>
<layout_stack name="bottom_bar_ls3">
diff --git a/indra/newview/skins/default/xui/it/panel_profile.xml b/indra/newview/skins/default/xui/it/panel_profile.xml
index 8a8d8f5846..c11adeda3d 100644
--- a/indra/newview/skins/default/xui/it/panel_profile.xml
+++ b/indra/newview/skins/default/xui/it/panel_profile.xml
@@ -53,7 +53,7 @@
<button label="Teleport" name="teleport" tool_tip="Offri teleport"/>
</layout_panel>
<layout_panel name="overflow_btn_lp">
- <button label="▼" name="overflow_btn" tool_tip="Paga del denaro o condividi qualcosa dall&apos;inventario con il residente"/>
+ <menu_button label="▼" name="overflow_btn" tool_tip="Paga del denaro o condividi qualcosa dall&apos;inventario con il residente"/>
</layout_panel>
</layout_stack>
</layout_panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_places.xml b/indra/newview/skins/default/xui/ja/panel_places.xml
index 3e364c9b3a..e19b86e552 100644
--- a/indra/newview/skins/default/xui/ja/panel_places.xml
+++ b/indra/newview/skins/default/xui/ja/panel_places.xml
@@ -21,7 +21,7 @@
<button label="編集" name="edit_btn" tool_tip="ランドマークの情報を編集します"/>
</layout_panel>
<layout_panel name="overflow_btn_lp">
- <button label="▼" name="overflow_btn" tool_tip="オプションを表示します"/>
+ <menu_button label="▼" name="overflow_btn" tool_tip="オプションを表示します"/>
</layout_panel>
</layout_stack>
<layout_stack name="bottom_bar_ls3">
diff --git a/indra/newview/skins/default/xui/ja/panel_profile.xml b/indra/newview/skins/default/xui/ja/panel_profile.xml
index 860020c87c..c2ffd74ec0 100644
--- a/indra/newview/skins/default/xui/ja/panel_profile.xml
+++ b/indra/newview/skins/default/xui/ja/panel_profile.xml
@@ -57,7 +57,7 @@
<button label="テレポート" name="teleport" tool_tip="テレポートを送ります"/>
</layout_panel>
<layout_panel name="overflow_btn_lp">
- <button label="▼" name="overflow_btn" tool_tip="住人にお金を渡すか持ち物を共有します"/>
+ <menu_button label="▼" name="overflow_btn" tool_tip="住人にお金を渡すか持ち物を共有します"/>
</layout_panel>
</layout_stack>
</layout_panel>
diff --git a/indra/newview/skins/default/xui/nl/floater_tools.xml b/indra/newview/skins/default/xui/nl/floater_tools.xml
index d49ffc2f51..4ffe675831 100644
--- a/indra/newview/skins/default/xui/nl/floater_tools.xml
+++ b/indra/newview/skins/default/xui/nl/floater_tools.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="toolbox floater" title="" short_title="BOUWEN" height="587">
+<floater name="toolbox floater" title="" short_title="BOUWEN" height="592">
<button label="" label_selected="" name="button focus" tool_tip="Focus"/>
<button label="" label_selected="" name="button move" tool_tip="Verplaats"/>
<button label="" label_selected="" name="button edit" tool_tip="Bewerk"/>
@@ -81,13 +81,13 @@
<text name="Strength:">
Sterkte
</text>
- <text name="obj_count" top_pad="15">
+ <text name="obj_count" top_pad="20">
Geselecteerde objecten: [COUNT]
</text>
<text name="prim_count">
primitieven: [COUNT]
</text>
- <tab_container name="Object Info Tabs" tab_max_width="62" tab_min_width="30" top="180">
+ <tab_container name="Object Info Tabs" tab_max_width="62" tab_min_width="30" top="185">
<panel label="Algemeen" name="General">
<text name="Name:">
Naam:
@@ -115,19 +115,19 @@
<text name="Group Name Proxy">
De Lindens
</text>
- <button label="Instellen..." label_selected="Instellen..." name="button set group" left_pad="13"/>
+ <button label="Instellen..." label_selected="Instellen..." name="button set group"/>
<text name="Permissions:">
Permissies:
</text>
- <check_box label="Deel met groep" name="checkbox share with group" tool_tip="Alle leden van de ingestelde groep toestaan om te delen en uw permissies voor dit object te gebruiken. U moet &apos;Overdragen&apos; om rolbeperkingen in te schakelen." left="100"/>
+ <check_box label="Deel met groep" name="checkbox share with group" tool_tip="Alle leden van de ingestelde groep toestaan om te delen en uw permissies voor dit object te gebruiken. U moet &apos;Overdragen&apos; om rolbeperkingen in te schakelen."/>
<string name="text deed continued">
Overdragen...
</string>
<string name="text deed">
Overdragen
</string>
- <button label="Overdragen..." label_selected="Overdragen..." name="button deed" tool_tip="Groepgedeelde objecten kunnen door een groepofficier worden overgedragen" left_pad="19"/>
+ <button label="Overdragen..." label_selected="Overdragen..." name="button deed" tool_tip="Groepgedeelde objecten kunnen door een groepofficier worden overgedragen"/>
<check_box label="Iedereen mag verplaatsen" name="checkbox allow everyone move"/>
<check_box label="Iedereen mag kopiëren" name="checkbox allow everyone copy"/>
<check_box label="Toon in zoeken" name="search_check" tool_tip="Laat mensen dit object zien in zoekresultaten"/>
diff --git a/indra/newview/skins/default/xui/pl/floater_tools.xml b/indra/newview/skins/default/xui/pl/floater_tools.xml
index 8c77df9248..7c1ced0eae 100644
--- a/indra/newview/skins/default/xui/pl/floater_tools.xml
+++ b/indra/newview/skins/default/xui/pl/floater_tools.xml
@@ -307,7 +307,7 @@
<combo_box.item label="Kwadrat" name="Square"/>
<combo_box.item label="Trójkąt" name="Triangle"/>
</combo_box>
- <text name="text twist">
+ <text name="text twist" left_delta="-5" width="160">
Skręcenie (początek/koniec)
</text>
<spinner label="P" name="Twist Begin"/>
diff --git a/indra/newview/skins/default/xui/pl/panel_places.xml b/indra/newview/skins/default/xui/pl/panel_places.xml
index e0a0cfd96a..34c105225d 100644
--- a/indra/newview/skins/default/xui/pl/panel_places.xml
+++ b/indra/newview/skins/default/xui/pl/panel_places.xml
@@ -21,7 +21,7 @@
<button label="Edytuj" name="edit_btn" tool_tip="Edytuj informacje landmarka"/>
</layout_panel>
<layout_panel name="overflow_btn_lp">
- <button label="▼" name="overflow_btn" tool_tip="Pokaż opcje dodatkowe"/>
+ <menu_button label="▼" name="overflow_btn" tool_tip="Pokaż opcje dodatkowe"/>
</layout_panel>
</layout_stack>
<layout_stack name="bottom_bar_ls3">
diff --git a/indra/newview/skins/default/xui/pl/panel_profile.xml b/indra/newview/skins/default/xui/pl/panel_profile.xml
index f4a5699f8d..4152c00386 100644
--- a/indra/newview/skins/default/xui/pl/panel_profile.xml
+++ b/indra/newview/skins/default/xui/pl/panel_profile.xml
@@ -42,7 +42,7 @@
<button label="Teleportuj" name="teleport" tool_tip="Teleportuj"/>
</layout_panel>
<layout_panel name="overflow_btn_lp">
- <button label="▼" name="overflow_btn" tool_tip="Zapłać lub udostępnij obiekt Rezydentowi"/>
+ <menu_button label="▼" name="overflow_btn" tool_tip="Zapłać lub udostępnij obiekt Rezydentowi"/>
</layout_panel>
</layout_stack>
</layout_panel>
diff --git a/indra/newview/skins/default/xui/pl/strings.xml b/indra/newview/skins/default/xui/pl/strings.xml
index 59daa26bf0..ea8bdd75b9 100644
--- a/indra/newview/skins/default/xui/pl/strings.xml
+++ b/indra/newview/skins/default/xui/pl/strings.xml
@@ -3469,7 +3469,7 @@ Jeżeli nadal otrzymujesz ten komunikat, skontaktuj się z [SUPPORT_SITE].
Rozmowa głosowa zakończona
</string>
<string name="conference-title-incoming">
- Konferencja z [AGENT_NAME]
+ Konferencja z [AGENT_NAME]
</string>
<string name="no_session_message">
(Sesja IM wygasła)
diff --git a/indra/newview/skins/default/xui/pt/floater_tools.xml b/indra/newview/skins/default/xui/pt/floater_tools.xml
index 2925e286ed..bd5fbf80d1 100644
--- a/indra/newview/skins/default/xui/pt/floater_tools.xml
+++ b/indra/newview/skins/default/xui/pt/floater_tools.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater name="toolbox floater" short_title="BUILD TOOLS" title="" width="288">
+<floater name="toolbox floater" short_title="BUILD TOOLS" title="">
<floater.string name="status_rotate">
Arrastar as faixas coloridas para girar o objeto
</floater.string>
diff --git a/indra/newview/skins/default/xui/pt/panel_places.xml b/indra/newview/skins/default/xui/pt/panel_places.xml
index 2e443bc057..828ef3e469 100644
--- a/indra/newview/skins/default/xui/pt/panel_places.xml
+++ b/indra/newview/skins/default/xui/pt/panel_places.xml
@@ -21,7 +21,7 @@
<button label="Editar" name="edit_btn" tool_tip="Editar dados do marco"/>
</layout_panel>
<layout_panel name="overflow_btn_lp">
- <button label="▼" name="overflow_btn" tool_tip="Mostrar opções adicionais"/>
+ <menu_button label="▼" name="overflow_btn" tool_tip="Mostrar opções adicionais"/>
</layout_panel>
</layout_stack>
<layout_stack name="bottom_bar_ls3">
diff --git a/indra/newview/skins/default/xui/pt/panel_profile.xml b/indra/newview/skins/default/xui/pt/panel_profile.xml
index e4200ae5da..f984ed6a7b 100644
--- a/indra/newview/skins/default/xui/pt/panel_profile.xml
+++ b/indra/newview/skins/default/xui/pt/panel_profile.xml
@@ -53,7 +53,7 @@
<button label="Teletransportar" name="teleport" tool_tip="Oferecer teletransporte"/>
</layout_panel>
<layout_panel name="overflow_btn_lp">
- <button label="▼" name="overflow_btn" tool_tip="Pagar ou compartilhar inventário com o residente"/>
+ <menu_button label="▼" name="overflow_btn" tool_tip="Pagar ou compartilhar inventário com o residente"/>
</layout_panel>
</layout_stack>
</layout_panel>
diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp
index db50b89620..309e9e9ee3 100644
--- a/indra/newview/tests/lllogininstance_test.cpp
+++ b/indra/newview/tests/lllogininstance_test.cpp
@@ -48,6 +48,9 @@ const std::string VIEWERLOGIN_GRIDLABEL("viewerlogin_grid");
const std::string APPVIEWER_SERIALNUMBER("appviewer_serialno");
+const std::string VIEWERLOGIN_CHANNEL("invalid_channel");
+const std::string VIEWERLOGIN_VERSION_CHANNEL("invalid_version");
+
// Link seams.
//-----------------------------------------------------------------------------
@@ -160,7 +163,6 @@ std::string LLGridManager::getAppSLURLBase(const std::string& grid_name)
//-----------------------------------------------------------------------------
#include "../llviewercontrol.h"
LLControlGroup gSavedSettings("Global");
-std::string gCurrentVersion = "invalid_version";
LLControlGroup::LLControlGroup(const std::string& name) :
LLInstanceTracker<LLControlGroup, std::string>(name){}
@@ -177,6 +179,10 @@ BOOL LLControlGroup::declareString(const std::string& name, const std::string &i
#include "lluicolortable.h"
void LLUIColorTable::saveUserSettings(void)const {}
+//-----------------------------------------------------------------------------
+#include "../llversioninfo.h"
+const std::string &LLVersionInfo::getChannelAndVersion() { return VIEWERLOGIN_VERSION_CHANNEL; }
+const std::string &LLVersionInfo::getChannel() { return VIEWERLOGIN_CHANNEL; }
//-----------------------------------------------------------------------------
#include "llnotifications.h"
@@ -290,7 +296,6 @@ namespace tut
gSavedSettings.declareBOOL("UseDebugMenus", FALSE, "", FALSE);
gSavedSettings.declareBOOL("ForceMandatoryUpdate", FALSE, "", FALSE);
gSavedSettings.declareString("ClientSettingsFile", "test_settings.xml", "", FALSE);
- gSavedSettings.declareString("VersionChannelName", "test_version_string", "", FALSE);
gSavedSettings.declareString("NextLoginLocation", "", "", FALSE);
gSavedSettings.declareBOOL("LoginLastLocation", FALSE, "", FALSE);
diff --git a/indra/newview/tests/llremoteparcelrequest_test.cpp b/indra/newview/tests/llremoteparcelrequest_test.cpp
new file mode 100644
index 0000000000..a6c1f69c82
--- /dev/null
+++ b/indra/newview/tests/llremoteparcelrequest_test.cpp
@@ -0,0 +1,134 @@
+/**
+ * @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);
+ }
+}
diff --git a/indra/newview/tests/llversioninfo_test.cpp b/indra/newview/tests/llversioninfo_test.cpp
new file mode 100644
index 0000000000..398d8f16ed
--- /dev/null
+++ b/indra/newview/tests/llversioninfo_test.cpp
@@ -0,0 +1,114 @@
+/**
+ * @file llversioninfo_test.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$
+ */
+
+#include "linden_common.h"
+
+#include "../test/lltut.h"
+
+#include "../llversioninfo.h"
+#include "llversionviewer.h"
+
+namespace tut
+{
+ struct versioninfo
+ {
+ versioninfo()
+ : mResetChannel("Reset Channel")
+ {
+ std::ostringstream stream;
+ stream << LL_VERSION_MAJOR << "."
+ << LL_VERSION_MINOR << "."
+ << LL_VERSION_PATCH << "."
+ << LL_VERSION_BUILD;
+ mVersion = stream.str();
+ stream.str("");
+
+ stream << LL_VERSION_MAJOR << "."
+ << LL_VERSION_MINOR << "."
+ << LL_VERSION_PATCH;
+ mShortVersion = stream.str();
+ stream.str("");
+
+ stream << LL_CHANNEL
+ << " "
+ << mVersion;
+ mVersionAndChannel = stream.str();
+ stream.str("");
+
+ stream << mResetChannel
+ << " "
+ << mVersion;
+ mResetVersionAndChannel = stream.str();
+ }
+ std::string mResetChannel;
+ std::string mVersion;
+ std::string mShortVersion;
+ std::string mVersionAndChannel;
+ std::string mResetVersionAndChannel;
+ };
+
+ typedef test_group<versioninfo> versioninfo_t;
+ typedef versioninfo_t::object versioninfo_object_t;
+ tut::versioninfo_t tut_versioninfo("LLVersionInfo");
+
+ template<> template<>
+ void versioninfo_object_t::test<1>()
+ {
+ ensure_equals("Major version",
+ LLVersionInfo::getMajor(),
+ LL_VERSION_MAJOR);
+ ensure_equals("Minor version",
+ LLVersionInfo::getMinor(),
+ LL_VERSION_MINOR);
+ ensure_equals("Patch version",
+ LLVersionInfo::getPatch(),
+ LL_VERSION_PATCH);
+ ensure_equals("Build version",
+ LLVersionInfo::getBuild(),
+ LL_VERSION_BUILD);
+ ensure_equals("Channel version",
+ LLVersionInfo::getChannel(),
+ LL_CHANNEL);
+
+ ensure_equals("Version String",
+ LLVersionInfo::getVersion(),
+ mVersion);
+ ensure_equals("Short Version String",
+ LLVersionInfo::getShortVersion(),
+ mShortVersion);
+ ensure_equals("Version and channel String",
+ LLVersionInfo::getChannelAndVersion(),
+ mVersionAndChannel);
+
+ LLVersionInfo::resetChannel(mResetChannel);
+ ensure_equals("Reset channel version",
+ LLVersionInfo::getChannel(),
+ mResetChannel);
+
+ ensure_equals("Reset Version and channel String",
+ LLVersionInfo::getChannelAndVersion(),
+ mResetVersionAndChannel);
+ }
+}
diff --git a/indra/newview/tests/llviewerhelputil_test.cpp b/indra/newview/tests/llviewerhelputil_test.cpp
index a0f1d1c3c3..b425b50c8b 100644
--- a/indra/newview/tests/llviewerhelputil_test.cpp
+++ b/indra/newview/tests/llviewerhelputil_test.cpp
@@ -72,16 +72,13 @@ static void substitute_string(std::string &input, const std::string &search, con
}
}
-class LLAgent
-{
-public:
- LLAgent() {}
- ~LLAgent() {}
-#ifdef __GNUC__
- __attribute__ ((noinline))
-#endif
- bool isGodlike() const { return FALSE; }
-};
+#include "../llagent.h"
+LLAgent::LLAgent() : mAgentAccess(gSavedSettings) { }
+LLAgent::~LLAgent() { }
+bool LLAgent::isGodlike() const { return FALSE; }
+LLAgentAccess::LLAgentAccess(LLControlGroup& settings) : mSavedSettings(settings) { }
+LLUIColor::LLUIColor() {}
+
LLAgent gAgent;
std::string LLWeb::expandURLSubstitutions(const std::string &url,
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 6861f02bfb..6c77f8ec38 100644
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -247,6 +247,8 @@ class WindowsManifest(ViewerManifest):
self.disable_manifest_check()
+ self.path(src="../viewer_components/updater/scripts/windows/update_install.bat", dst="update_install.bat")
+
# Get shared libs from the shared libs staging directory
if self.prefix(src=os.path.join(os.pardir, 'sharedlibs', self.args['configuration']),
dst=""):
@@ -572,6 +574,8 @@ class DarwinManifest(ViewerManifest):
# copy additional libs in <bundle>/Contents/MacOS/
self.path("../../libraries/universal-darwin/lib_release/libndofdev.dylib", dst="MacOS/libndofdev.dylib")
+ self.path("../viewer_components/updater/scripts/darwin/update_install", "MacOS/update_install")
+
# most everything goes in the Resources directory
if self.prefix(src="", dst="Resources"):
super(DarwinManifest, self).construct()
@@ -707,6 +711,11 @@ class DarwinManifest(ViewerManifest):
self.run_command('strip -S %(viewer_binary)r' %
{ 'viewer_binary' : self.dst_path_of('Contents/MacOS/Second Life')})
+ def copy_finish(self):
+ # Force executable permissions to be set for scripts
+ # see CHOP-223 and http://mercurial.selenic.com/bts/issue1802
+ for script in 'Contents/MacOS/update_install',:
+ self.run_command("chmod +x %r" % os.path.join(self.get_dst_prefix(), script))
def package_finish(self):
channel_standin = 'Second Life Viewer 2' # hah, our default channel is not usable on its own
@@ -743,6 +752,11 @@ class DarwinManifest(ViewerManifest):
devfile = re.search("/dev/disk([0-9]+)[^s]", hdi_output).group(0).strip()
volpath = re.search('HFS\s+(.+)', hdi_output).group(1).strip()
+ if devfile != '/dev/disk1':
+ # adding more debugging info based upon nat's hunches to the
+ # logs to help track down 'SetFile -a V' failures -brad
+ print "WARNING: 'SetFile -a V' command below is probably gonna fail"
+
# Copy everything in to the mounted .dmg
if self.default_channel() and not self.default_grid():
@@ -842,6 +856,8 @@ class LinuxManifest(ViewerManifest):
# recurse
self.end_prefix("res-sdl")
+ self.path("../viewer_components/updater/scripts/linux/update_install", "bin/update_install")
+
# plugins
if self.prefix(src="", dst="bin/llplugin"):
self.path("../media_plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so")
@@ -855,6 +871,12 @@ class LinuxManifest(ViewerManifest):
self.path("featuretable_linux.txt")
+ def copy_finish(self):
+ # Force executable permissions to be set for scripts
+ # see CHOP-223 and http://mercurial.selenic.com/bts/issue1802
+ for script in 'secondlife', 'bin/update_install':
+ self.run_command("chmod +x %r" % os.path.join(self.get_dst_prefix(), script))
+
def package_finish(self):
if 'installer_name' in self.args:
installer_name = self.args['installer_name']
@@ -870,7 +892,7 @@ class LinuxManifest(ViewerManifest):
if self.args['buildtype'].lower() == 'release' and self.is_packaging_viewer():
print "* Going strip-crazy on the packaged binaries, since this is a RELEASE build"
- self.run_command("find %(d)r/bin %(d)r/lib -type f | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} ) # makes some small assumptions about our packaged dir structure
+ self.run_command("find %(d)r/bin %(d)r/lib -type f \\! -name update_install | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} ) # makes some small assumptions about our packaged dir structure
# Fix access permissions
self.run_command("""
@@ -897,6 +919,9 @@ class LinuxManifest(ViewerManifest):
'dir': self.get_build_prefix(),
'inst_name': installer_name,
'inst_path':self.build_path_of(installer_name)})
+ else:
+ print "Skipping %s.tar.bz2 for non-Release build (%s)" % \
+ (installer_name, self.args['buildtype'])
finally:
self.run_command("mv %(inst)s %(dst)s" % {
'dst': self.get_dst_prefix(),
diff --git a/indra/viewer_components/CMakeLists.txt b/indra/viewer_components/CMakeLists.txt
index 0993b64b14..74c9b4568d 100644
--- a/indra/viewer_components/CMakeLists.txt
+++ b/indra/viewer_components/CMakeLists.txt
@@ -1,4 +1,4 @@
# -*- cmake -*-
add_subdirectory(login)
-
+add_subdirectory(updater)
diff --git a/indra/viewer_components/updater/CMakeLists.txt b/indra/viewer_components/updater/CMakeLists.txt
new file mode 100644
index 0000000000..0e288bb496
--- /dev/null
+++ b/indra/viewer_components/updater/CMakeLists.txt
@@ -0,0 +1,82 @@
+# -*- cmake -*-
+
+project(updater_service)
+
+include(00-Common)
+if(LL_TESTS)
+ include(LLAddBuildTest)
+endif(LL_TESTS)
+include(CMakeCopyIfDifferent)
+include(CURL)
+include(LLCommon)
+include(LLMessage)
+include(LLPlugin)
+include(LLVFS)
+
+include_directories(
+ ${LLCOMMON_INCLUDE_DIRS}
+ ${LLMESSAGE_INCLUDE_DIRS}
+ ${LLPLUGIN_INCLUDE_DIRS}
+ ${LLVFS_INCLUDE_DIRS}
+ ${CURL_INCLUDE_DIRS}
+ )
+
+set(updater_service_SOURCE_FILES
+ llupdaterservice.cpp
+ llupdatechecker.cpp
+ llupdatedownloader.cpp
+ llupdateinstaller.cpp
+ )
+
+set(updater_service_HEADER_FILES
+ llupdaterservice.h
+ llupdatechecker.h
+ llupdatedownloader.h
+ llupdateinstaller.h
+ )
+
+set_source_files_properties(${updater_service_HEADER_FILES}
+ PROPERTIES HEADER_FILE_ONLY TRUE)
+
+list(APPEND
+ updater_service_SOURCE_FILES
+ ${updater_service_HEADER_FILES}
+ )
+
+add_library(llupdaterservice
+ ${updater_service_SOURCE_FILES}
+ )
+
+target_link_libraries(llupdaterservice
+ ${LLCOMMON_LIBRARIES}
+ ${LLMESSAGE_LIBRARIES}
+ ${LLPLUGIN_LIBRARIES}
+ ${LLVFS_LIBRARIES}
+ )
+
+if(LL_TESTS)
+ SET(llupdater_service_TEST_SOURCE_FILES
+ llupdaterservice.cpp
+ )
+
+# *NOTE:Mani - I was trying to use the preprocessor seam to mock out
+# llifstream (and other) llcommon classes. I didn't work
+# because of the windows declspec(dllimport)attribute.
+#set_source_files_properties(
+# llupdaterservice.cpp
+# PROPERTIES
+# LL_TEST_ADDITIONAL_CFLAGS "-Dllifstream=llus_mock_llifstream"
+# )
+
+ LL_ADD_PROJECT_UNIT_TESTS(llupdaterservice "${llupdater_service_TEST_SOURCE_FILES}")
+endif(LL_TESTS)
+
+set(UPDATER_INCLUDE_DIRS
+ ${LIBS_OPEN_DIR}/viewer_components/updater
+ CACHE INTERNAL ""
+)
+
+set(UPDATER_LIBRARIES
+ llupdaterservice
+ CACHE INTERNAL ""
+)
diff --git a/indra/viewer_components/updater/llupdatechecker.cpp b/indra/viewer_components/updater/llupdatechecker.cpp
new file mode 100644
index 0000000000..c6aa9b0f11
--- /dev/null
+++ b/indra/viewer_components/updater/llupdatechecker.cpp
@@ -0,0 +1,194 @@
+/**
+ * @file 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$
+ */
+
+#include "linden_common.h"
+#include <stdexcept>
+#include <boost/format.hpp>
+#include "llhttpclient.h"
+#include "llsd.h"
+#include "llupdatechecker.h"
+#include "lluri.h"
+
+
+#if LL_WINDOWS
+#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
+#endif
+
+
+class LLUpdateChecker::CheckError:
+ public std::runtime_error
+{
+public:
+ CheckError(const char * message):
+ std::runtime_error(message)
+ {
+ ; // No op.
+ }
+};
+
+
+class LLUpdateChecker::Implementation:
+ public LLHTTPClient::Responder
+{
+public:
+ Implementation(Client & client);
+ ~Implementation();
+ void check(std::string const & protocolVersion, std::string const & hostUrl,
+ std::string const & servicePath, std::string channel, std::string version);
+
+ // Responder:
+ virtual void completed(U32 status,
+ const std::string & reason,
+ const LLSD& content);
+ virtual void error(U32 status, const std::string & reason);
+
+private:
+ static const char * sProtocolVersion;
+
+ Client & mClient;
+ LLHTTPClient mHttpClient;
+ bool mInProgress;
+ std::string mVersion;
+
+ std::string buildUrl(std::string const & protocolVersion, std::string const & hostUrl,
+ std::string const & servicePath, std::string channel, std::string version);
+
+ LOG_CLASS(LLUpdateChecker::Implementation);
+};
+
+
+
+// LLUpdateChecker
+//-----------------------------------------------------------------------------
+
+
+LLUpdateChecker::LLUpdateChecker(LLUpdateChecker::Client & client):
+ mImplementation(new LLUpdateChecker::Implementation(client))
+{
+ ; // No op.
+}
+
+
+void LLUpdateChecker::check(std::string const & protocolVersion, std::string const & hostUrl,
+ std::string const & servicePath, std::string channel, std::string version)
+{
+ mImplementation->check(protocolVersion, hostUrl, servicePath, channel, version);
+}
+
+
+
+// LLUpdateChecker::Implementation
+//-----------------------------------------------------------------------------
+
+
+const char * LLUpdateChecker::Implementation::sProtocolVersion = "v1.0";
+
+
+LLUpdateChecker::Implementation::Implementation(LLUpdateChecker::Client & client):
+ mClient(client),
+ mInProgress(false)
+{
+ ; // No op.
+}
+
+
+LLUpdateChecker::Implementation::~Implementation()
+{
+ ; // No op.
+}
+
+
+void LLUpdateChecker::Implementation::check(std::string const & protocolVersion, std::string const & hostUrl,
+ std::string const & servicePath, std::string channel, std::string version)
+{
+ llassert(!mInProgress);
+
+ if(protocolVersion != sProtocolVersion) throw CheckError("unsupported protocol");
+
+ mInProgress = true;
+ mVersion = version;
+ std::string checkUrl = buildUrl(protocolVersion, hostUrl, servicePath, channel, version);
+ LL_INFOS("UpdateCheck") << "checking for updates at " << checkUrl << llendl;
+
+ // The HTTP client will wrap a raw pointer in a boost::intrusive_ptr causing the
+ // passed object to be silently and automatically deleted. We pass a self-
+ // referential intrusive pointer to which we add a reference to keep the
+ // client from deleting the update checker implementation instance.
+ LLHTTPClient::ResponderPtr temporaryPtr(this);
+ boost::intrusive_ptr_add_ref(temporaryPtr.get());
+ mHttpClient.get(checkUrl, temporaryPtr);
+}
+
+void LLUpdateChecker::Implementation::completed(U32 status,
+ const std::string & reason,
+ const LLSD & content)
+{
+ mInProgress = false;
+
+ if(status != 200) {
+ LL_WARNS("UpdateCheck") << "html error " << status << " (" << reason << ")" << llendl;
+ mClient.error(reason);
+ } else if(!content.asBoolean()) {
+ LL_INFOS("UpdateCheck") << "up to date" << llendl;
+ mClient.upToDate();
+ } else if(content["required"].asBoolean()) {
+ LL_INFOS("UpdateCheck") << "version invalid" << llendl;
+ LLURI uri(content["url"].asString());
+ mClient.requiredUpdate(content["version"].asString(), uri, content["hash"].asString());
+ } else {
+ LL_INFOS("UpdateCheck") << "newer version " << content["version"].asString() << " available" << llendl;
+ LLURI uri(content["url"].asString());
+ mClient.optionalUpdate(content["version"].asString(), uri, content["hash"].asString());
+ }
+}
+
+
+void LLUpdateChecker::Implementation::error(U32 status, const std::string & reason)
+{
+ mInProgress = false;
+ LL_WARNS("UpdateCheck") << "update check failed; " << reason << llendl;
+ mClient.error(reason);
+}
+
+
+std::string LLUpdateChecker::Implementation::buildUrl(std::string const & protocolVersion, std::string const & hostUrl,
+ std::string const & servicePath, std::string channel, std::string version)
+{
+#ifdef LL_WINDOWS
+ static const char * platform = "win";
+#elif LL_DARWIN
+ static const char * platform = "mac";
+#else
+ static const char * platform = "lnx";
+#endif
+
+ LLSD path;
+ path.append(servicePath);
+ path.append(protocolVersion);
+ path.append(channel);
+ path.append(version);
+ path.append(platform);
+ return LLURI::buildHTTP(hostUrl, path).asString();
+}
diff --git a/indra/viewer_components/updater/llupdatechecker.h b/indra/viewer_components/updater/llupdatechecker.h
new file mode 100644
index 0000000000..cea1f13647
--- /dev/null
+++ b/indra/viewer_components/updater/llupdatechecker.h
@@ -0,0 +1,82 @@
+/**
+ * @file llupdatechecker.h
+ *
+ * $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_UPDATERCHECKER_H
+#define LL_UPDATERCHECKER_H
+
+
+#include <boost/shared_ptr.hpp>
+
+
+//
+// Implements asynchronous checking for updates.
+//
+class LLUpdateChecker {
+public:
+ class Client;
+ class Implementation;
+
+ // An exception that may be raised on check errors.
+ class CheckError;
+
+ LLUpdateChecker(Client & client);
+
+ // Check status of current app on the given host for the channel and version provided.
+ void check(std::string const & protocolVersion, std::string const & hostUrl,
+ std::string const & servicePath, std::string channel, std::string version);
+
+private:
+ boost::shared_ptr<Implementation> mImplementation;
+};
+
+
+class LLURI; // From lluri.h
+
+
+//
+// The client interface implemented by a requestor checking for an update.
+//
+class LLUpdateChecker::Client
+{
+public:
+ // An error occurred while checking for an update.
+ virtual void error(std::string const & message) = 0;
+
+ // A newer version is available, but the current version may still be used.
+ virtual void optionalUpdate(std::string const & newVersion,
+ LLURI const & uri,
+ std::string const & hash) = 0;
+
+ // A newer version is available, and the current version is no longer valid.
+ virtual void requiredUpdate(std::string const & newVersion,
+ LLURI const & uri,
+ std::string const & hash) = 0;
+
+ // The checked version is up to date; no newer version exists.
+ virtual void upToDate(void) = 0;
+};
+
+
+#endif
diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp
new file mode 100644
index 0000000000..c17a50e242
--- /dev/null
+++ b/indra/viewer_components/updater/llupdatedownloader.cpp
@@ -0,0 +1,428 @@
+/**
+ * @file llupdatedownloader.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$
+ */
+
+#include "linden_common.h"
+#include <stdexcept>
+#include <boost/format.hpp>
+#include <boost/lexical_cast.hpp>
+#include <curl/curl.h>
+#include "lldir.h"
+#include "llfile.h"
+#include "llmd5.h"
+#include "llsd.h"
+#include "llsdserialize.h"
+#include "llthread.h"
+#include "llupdatedownloader.h"
+#include "llupdaterservice.h"
+
+
+class LLUpdateDownloader::Implementation:
+ public LLThread
+{
+public:
+ Implementation(LLUpdateDownloader::Client & client);
+ ~Implementation();
+ void cancel(void);
+ void download(LLURI const & uri, std::string const & hash);
+ bool isDownloading(void);
+ size_t onHeader(void * header, size_t size);
+ size_t onBody(void * header, size_t size);
+ void resume(void);
+
+private:
+ bool mCancelled;
+ LLUpdateDownloader::Client & mClient;
+ CURL * mCurl;
+ LLSD mDownloadData;
+ llofstream mDownloadStream;
+ std::string mDownloadRecordPath;
+ curl_slist * mHeaderList;
+
+ void initializeCurlGet(std::string const & url, bool processHeader);
+ void resumeDownloading(size_t startByte);
+ void run(void);
+ void startDownloading(LLURI const & uri, std::string const & hash);
+ void throwOnCurlError(CURLcode code);
+ bool validateDownload(void);
+
+ LOG_CLASS(LLUpdateDownloader::Implementation);
+};
+
+
+namespace {
+ class DownloadError:
+ public std::runtime_error
+ {
+ public:
+ DownloadError(const char * message):
+ std::runtime_error(message)
+ {
+ ; // No op.
+ }
+ };
+
+
+ const char * gSecondLifeUpdateRecord = "SecondLifeUpdateDownload.xml";
+};
+
+
+
+// LLUpdateDownloader
+//-----------------------------------------------------------------------------
+
+
+
+std::string LLUpdateDownloader::downloadMarkerPath(void)
+{
+ return gDirUtilp->getExpandedFilename(LL_PATH_LOGS, gSecondLifeUpdateRecord);
+}
+
+
+LLUpdateDownloader::LLUpdateDownloader(Client & client):
+ mImplementation(new LLUpdateDownloader::Implementation(client))
+{
+ ; // No op.
+}
+
+
+void LLUpdateDownloader::cancel(void)
+{
+ mImplementation->cancel();
+}
+
+
+void LLUpdateDownloader::download(LLURI const & uri, std::string const & hash)
+{
+ mImplementation->download(uri, hash);
+}
+
+
+bool LLUpdateDownloader::isDownloading(void)
+{
+ return mImplementation->isDownloading();
+}
+
+
+void LLUpdateDownloader::resume(void)
+{
+ mImplementation->resume();
+}
+
+
+
+// LLUpdateDownloader::Implementation
+//-----------------------------------------------------------------------------
+
+
+namespace {
+ size_t write_function(void * data, size_t blockSize, size_t blocks, void * downloader)
+ {
+ size_t bytes = blockSize * blocks;
+ return reinterpret_cast<LLUpdateDownloader::Implementation *>(downloader)->onBody(data, bytes);
+ }
+
+
+ size_t header_function(void * data, size_t blockSize, size_t blocks, void * downloader)
+ {
+ size_t bytes = blockSize * blocks;
+ return reinterpret_cast<LLUpdateDownloader::Implementation *>(downloader)->onHeader(data, bytes);
+ }
+}
+
+
+LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client & client):
+ LLThread("LLUpdateDownloader"),
+ mCancelled(false),
+ mClient(client),
+ mCurl(0),
+ mHeaderList(0)
+{
+ CURLcode code = curl_global_init(CURL_GLOBAL_ALL); // Just in case.
+ llverify(code == CURLE_OK); // TODO: real error handling here.
+}
+
+
+LLUpdateDownloader::Implementation::~Implementation()
+{
+ if(isDownloading()) {
+ cancel();
+ shutdown();
+ } else {
+ ; // No op.
+ }
+ if(mCurl) curl_easy_cleanup(mCurl);
+}
+
+
+void LLUpdateDownloader::Implementation::cancel(void)
+{
+ mCancelled = true;
+}
+
+
+void LLUpdateDownloader::Implementation::download(LLURI const & uri, std::string const & hash)
+{
+ if(isDownloading()) mClient.downloadError("download in progress");
+
+ mDownloadRecordPath = downloadMarkerPath();
+ mDownloadData = LLSD();
+ try {
+ startDownloading(uri, hash);
+ } catch(DownloadError const & e) {
+ mClient.downloadError(e.what());
+ }
+}
+
+
+bool LLUpdateDownloader::Implementation::isDownloading(void)
+{
+ return !isStopped();
+}
+
+
+void LLUpdateDownloader::Implementation::resume(void)
+{
+ mCancelled = false;
+
+ if(isDownloading()) {
+ mClient.downloadError("download in progress");
+ }
+
+ mDownloadRecordPath = downloadMarkerPath();
+ llifstream dataStream(mDownloadRecordPath);
+ if(!dataStream) {
+ mClient.downloadError("no download marker");
+ return;
+ }
+
+ LLSDSerialize::fromXMLDocument(mDownloadData, dataStream);
+
+ if(!mDownloadData.asBoolean()) {
+ mClient.downloadError("no download information in marker");
+ return;
+ }
+
+ std::string filePath = mDownloadData["path"].asString();
+ try {
+ if(LLFile::isfile(filePath)) {
+ llstat fileStatus;
+ LLFile::stat(filePath, &fileStatus);
+ if(fileStatus.st_size != mDownloadData["size"].asInteger()) {
+ resumeDownloading(fileStatus.st_size);
+ } else if(!validateDownload()) {
+ LLFile::remove(filePath);
+ download(LLURI(mDownloadData["url"].asString()), mDownloadData["hash"].asString());
+ } else {
+ mClient.downloadComplete(mDownloadData);
+ }
+ } else {
+ download(LLURI(mDownloadData["url"].asString()), mDownloadData["hash"].asString());
+ }
+ } catch(DownloadError & e) {
+ mClient.downloadError(e.what());
+ }
+}
+
+
+size_t LLUpdateDownloader::Implementation::onHeader(void * buffer, size_t size)
+{
+ char const * headerPtr = reinterpret_cast<const char *> (buffer);
+ std::string header(headerPtr, headerPtr + size);
+ size_t colonPosition = header.find(':');
+ if(colonPosition == std::string::npos) return size; // HTML response; ignore.
+
+ if(header.substr(0, colonPosition) == "Content-Length") {
+ try {
+ size_t firstDigitPos = header.find_first_of("0123456789", colonPosition);
+ size_t lastDigitPos = header.find_last_of("0123456789");
+ std::string contentLength = header.substr(firstDigitPos, lastDigitPos - firstDigitPos + 1);
+ size_t size = boost::lexical_cast<size_t>(contentLength);
+ LL_INFOS("UpdateDownload") << "download size is " << size << LL_ENDL;
+
+ mDownloadData["size"] = LLSD(LLSD::Integer(size));
+ llofstream odataStream(mDownloadRecordPath);
+ LLSDSerialize::toPrettyXML(mDownloadData, odataStream);
+ } catch (std::exception const & e) {
+ LL_WARNS("UpdateDownload") << "unable to read content length ("
+ << e.what() << ")" << LL_ENDL;
+ }
+ } else {
+ ; // No op.
+ }
+
+ return size;
+}
+
+
+size_t LLUpdateDownloader::Implementation::onBody(void * buffer, size_t size)
+{
+ if(mCancelled) return 0; // Forces a write error which will halt curl thread.
+ if((size == 0) || (buffer == 0)) return 0;
+
+ mDownloadStream.write(reinterpret_cast<const char *>(buffer), size);
+ if(mDownloadStream.bad()) {
+ return 0;
+ } else {
+ return size;
+ }
+}
+
+
+void LLUpdateDownloader::Implementation::run(void)
+{
+ CURLcode code = curl_easy_perform(mCurl);
+ mDownloadStream.close();
+ if(code == CURLE_OK) {
+ LLFile::remove(mDownloadRecordPath);
+ if(validateDownload()) {
+ LL_INFOS("UpdateDownload") << "download successful" << LL_ENDL;
+ mClient.downloadComplete(mDownloadData);
+ } else {
+ LL_INFOS("UpdateDownload") << "download failed hash check" << LL_ENDL;
+ std::string filePath = mDownloadData["path"].asString();
+ if(filePath.size() != 0) LLFile::remove(filePath);
+ mClient.downloadError("failed hash check");
+ }
+ } else if(mCancelled && (code == CURLE_WRITE_ERROR)) {
+ LL_INFOS("UpdateDownload") << "download canceled by user" << LL_ENDL;
+ // Do not call back client.
+ } else {
+ LL_WARNS("UpdateDownload") << "download failed with error '" <<
+ curl_easy_strerror(code) << "'" << LL_ENDL;
+ LLFile::remove(mDownloadRecordPath);
+ if(mDownloadData.has("path")) LLFile::remove(mDownloadData["path"].asString());
+ mClient.downloadError("curl error");
+ }
+
+ if(mHeaderList) {
+ curl_slist_free_all(mHeaderList);
+ mHeaderList = 0;
+ }
+}
+
+
+void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & url, bool processHeader)
+{
+ if(mCurl == 0) {
+ mCurl = curl_easy_init();
+ } else {
+ curl_easy_reset(mCurl);
+ }
+
+ if(mCurl == 0) throw DownloadError("failed to initialize curl");
+
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_NOSIGNAL, true));
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_FOLLOWLOCATION, true));
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_WRITEFUNCTION, &write_function));
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_WRITEDATA, this));
+ if(processHeader) {
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HEADERFUNCTION, &header_function));
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HEADERDATA, this));
+ }
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPGET, true));
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_URL, url.c_str()));
+}
+
+
+void LLUpdateDownloader::Implementation::resumeDownloading(size_t startByte)
+{
+ LL_INFOS("UpdateDownload") << "resuming download from " << mDownloadData["url"].asString()
+ << " at byte " << startByte << LL_ENDL;
+
+ initializeCurlGet(mDownloadData["url"].asString(), false);
+
+ // The header 'Range: bytes n-' will request the bytes remaining in the
+ // source begining with byte n and ending with the last byte.
+ boost::format rangeHeaderFormat("Range: bytes=%u-");
+ rangeHeaderFormat % startByte;
+ mHeaderList = curl_slist_append(mHeaderList, rangeHeaderFormat.str().c_str());
+ if(mHeaderList == 0) throw DownloadError("cannot add Range header");
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPHEADER, mHeaderList));
+
+ mDownloadStream.open(mDownloadData["path"].asString(),
+ std::ios_base::out | std::ios_base::binary | std::ios_base::app);
+ start();
+}
+
+
+void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri, std::string const & hash)
+{
+ mDownloadData["url"] = uri.asString();
+ mDownloadData["hash"] = hash;
+ mDownloadData["current_version"] = ll_get_version();
+ LLSD path = uri.pathArray();
+ if(path.size() == 0) throw DownloadError("no file path");
+ std::string fileName = path[path.size() - 1].asString();
+ std::string filePath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, fileName);
+ mDownloadData["path"] = filePath;
+
+ LL_INFOS("UpdateDownload") << "downloading " << filePath
+ << " from " << uri.asString() << LL_ENDL;
+ LL_INFOS("UpdateDownload") << "hash of file is " << hash << LL_ENDL;
+
+ llofstream dataStream(mDownloadRecordPath);
+ LLSDSerialize::toPrettyXML(mDownloadData, dataStream);
+
+ mDownloadStream.open(filePath, std::ios_base::out | std::ios_base::binary);
+ initializeCurlGet(uri.asString(), true);
+ start();
+}
+
+
+void LLUpdateDownloader::Implementation::throwOnCurlError(CURLcode code)
+{
+ if(code != CURLE_OK) {
+ const char * errorString = curl_easy_strerror(code);
+ if(errorString != 0) {
+ throw DownloadError(curl_easy_strerror(code));
+ } else {
+ throw DownloadError("unknown curl error");
+ }
+ } else {
+ ; // No op.
+ }
+}
+
+
+bool LLUpdateDownloader::Implementation::validateDownload(void)
+{
+ std::string filePath = mDownloadData["path"].asString();
+ llifstream fileStream(filePath, std::ios_base::in | std::ios_base::binary);
+ if(!fileStream) return false;
+
+ std::string hash = mDownloadData["hash"].asString();
+ if(hash.size() != 0) {
+ LL_INFOS("UpdateDownload") << "checking hash..." << LL_ENDL;
+ char digest[33];
+ LLMD5(fileStream).hex_digest(digest);
+ if(hash != digest) {
+ LL_WARNS("UpdateDownload") << "download hash mismatch; expeted " << hash <<
+ " but download is " << digest << LL_ENDL;
+ }
+ return hash == digest;
+ } else {
+ return true; // No hash check provided.
+ }
+}
diff --git a/indra/viewer_components/updater/llupdatedownloader.h b/indra/viewer_components/updater/llupdatedownloader.h
new file mode 100644
index 0000000000..1b3d7480fd
--- /dev/null
+++ b/indra/viewer_components/updater/llupdatedownloader.h
@@ -0,0 +1,87 @@
+/**
+ * @file llupdatedownloader.h
+ *
+ * $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_UPDATE_DOWNLOADER_H
+#define LL_UPDATE_DOWNLOADER_H
+
+
+#include <string>
+#include <boost/shared_ptr.hpp>
+#include "lluri.h"
+
+
+//
+// An asynchronous download service for fetching updates.
+//
+class LLUpdateDownloader
+{
+public:
+ class Client;
+ class Implementation;
+
+ // Returns the path to the download marker file containing details of the
+ // latest download.
+ static std::string downloadMarkerPath(void);
+
+ LLUpdateDownloader(Client & client);
+
+ // Cancel any in progress download; a no op if none is in progress. The
+ // client will not receive a complete or error callback.
+ void cancel(void);
+
+ // Start a new download.
+ void download(LLURI const & uri, std::string const & hash);
+
+ // Returns true if a download is in progress.
+ bool isDownloading(void);
+
+ // Resume a partial download.
+ void resume(void);
+
+private:
+ boost::shared_ptr<Implementation> mImplementation;
+};
+
+
+//
+// An interface to be implemented by clients initiating a update download.
+//
+class LLUpdateDownloader::Client {
+public:
+
+ // The download has completed successfully.
+ // data is a map containing the following items:
+ // url - source (remote) location
+ // hash - the md5 sum that should match the installer file.
+ // path - destination (local) location
+ // size - the size of the installer in bytes
+ virtual void downloadComplete(LLSD const & data) = 0;
+
+ // The download failed.
+ virtual void downloadError(std::string const & message) = 0;
+};
+
+
+#endif
diff --git a/indra/viewer_components/updater/llupdateinstaller.cpp b/indra/viewer_components/updater/llupdateinstaller.cpp
new file mode 100644
index 0000000000..6e69bcf28b
--- /dev/null
+++ b/indra/viewer_components/updater/llupdateinstaller.cpp
@@ -0,0 +1,90 @@
+/**
+ * @file llupdateinstaller.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$
+ */
+
+#include "linden_common.h"
+#include <apr_file_io.h>
+#include "llapr.h"
+#include "llprocesslauncher.h"
+#include "llupdateinstaller.h"
+#include "lldir.h"
+
+
+namespace {
+ class RelocateError {};
+
+
+ std::string copy_to_temp(std::string const & path)
+ {
+ std::string scriptFile = gDirUtilp->getBaseFileName(path);
+ std::string newPath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, scriptFile);
+ apr_status_t status = apr_file_copy(path.c_str(), newPath.c_str(), APR_FILE_SOURCE_PERMS, gAPRPoolp);
+ if(status != APR_SUCCESS) throw RelocateError();
+
+ return newPath;
+ }
+}
+
+
+int ll_install_update(std::string const & script, std::string const & updatePath, LLInstallScriptMode mode)
+{
+ std::string actualScriptPath;
+ switch(mode) {
+ case LL_COPY_INSTALL_SCRIPT_TO_TEMP:
+ try {
+ actualScriptPath = copy_to_temp(script);
+ }
+ catch (RelocateError &) {
+ return -1;
+ }
+ break;
+ case LL_RUN_INSTALL_SCRIPT_IN_PLACE:
+ actualScriptPath = script;
+ break;
+ default:
+ llassert(!"unpossible copy mode");
+ }
+
+ llinfos << "UpdateInstaller: installing " << updatePath << " using " <<
+ actualScriptPath << LL_ENDL;
+
+ LLProcessLauncher launcher;
+ launcher.setExecutable(actualScriptPath);
+ launcher.addArgument(updatePath);
+ launcher.addArgument(ll_install_failed_marker_path().c_str());
+ int result = launcher.launch();
+ launcher.orphan();
+
+ return result;
+}
+
+
+std::string const & ll_install_failed_marker_path(void)
+{
+ static std::string path;
+ if(path.empty()) {
+ path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLifeInstallFailed.marker");
+ }
+ return path;
+}
diff --git a/indra/viewer_components/updater/llupdateinstaller.h b/indra/viewer_components/updater/llupdateinstaller.h
new file mode 100644
index 0000000000..6ce08ce6fa
--- /dev/null
+++ b/indra/viewer_components/updater/llupdateinstaller.h
@@ -0,0 +1,57 @@
+/**
+ * @file llupdateinstaller.h
+ *
+ * $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_UPDATE_INSTALLER_H
+#define LL_UPDATE_INSTALLER_H
+
+
+#include <string>
+
+
+enum LLInstallScriptMode {
+ LL_RUN_INSTALL_SCRIPT_IN_PLACE,
+ LL_COPY_INSTALL_SCRIPT_TO_TEMP
+};
+
+//
+// Launch the installation script.
+//
+// The updater will overwrite the current installation, so it is highly recommended
+// that the current application terminate once this function is called.
+//
+int ll_install_update(
+ std::string const & script, // Script to execute.
+ std::string const & updatePath, // Path to update file.
+ LLInstallScriptMode mode=LL_COPY_INSTALL_SCRIPT_TO_TEMP); // Run in place or copy to temp?
+
+
+//
+// Returns the path which points to the failed install marker file, should it
+// exist.
+//
+std::string const & ll_install_failed_marker_path(void);
+
+
+#endif
diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp
new file mode 100644
index 0000000000..cc60eaead2
--- /dev/null
+++ b/indra/viewer_components/updater/llupdaterservice.cpp
@@ -0,0 +1,519 @@
+/**
+ * @file 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$
+ */
+
+#include "linden_common.h"
+
+#include "llupdatedownloader.h"
+#include "llevents.h"
+#include "lltimer.h"
+#include "llupdaterservice.h"
+#include "llupdatechecker.h"
+#include "llupdateinstaller.h"
+#include "llversionviewer.h"
+
+#include <boost/scoped_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include "lldir.h"
+#include "llsdserialize.h"
+#include "llfile.h"
+
+#if LL_WINDOWS
+#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
+#endif
+
+
+namespace
+{
+ boost::weak_ptr<LLUpdaterServiceImpl> gUpdater;
+
+ const std::string UPDATE_MARKER_FILENAME("SecondLifeUpdateReady.xml");
+ std::string update_marker_path()
+ {
+ return gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
+ UPDATE_MARKER_FILENAME);
+ }
+
+ std::string install_script_path(void)
+ {
+#ifdef LL_WINDOWS
+ std::string scriptFile = "update_install.bat";
+#else
+ std::string scriptFile = "update_install";
+#endif
+ return gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, scriptFile);
+ }
+
+ LLInstallScriptMode install_script_mode(void)
+ {
+#ifdef LL_WINDOWS
+ return LL_COPY_INSTALL_SCRIPT_TO_TEMP;
+#else
+ return LL_RUN_INSTALL_SCRIPT_IN_PLACE;
+#endif
+ };
+
+}
+
+class LLUpdaterServiceImpl :
+ public LLUpdateChecker::Client,
+ public LLUpdateDownloader::Client
+{
+ static const std::string sListenerName;
+
+ std::string mProtocolVersion;
+ std::string mUrl;
+ std::string mPath;
+ std::string mChannel;
+ std::string mVersion;
+
+ unsigned int mCheckPeriod;
+ bool mIsChecking;
+ bool mIsDownloading;
+
+ LLUpdateChecker mUpdateChecker;
+ LLUpdateDownloader mUpdateDownloader;
+ LLTimer mTimer;
+
+ LLUpdaterService::app_exit_callback_t mAppExitCallback;
+
+ LOG_CLASS(LLUpdaterServiceImpl);
+
+public:
+ LLUpdaterServiceImpl();
+ virtual ~LLUpdaterServiceImpl();
+
+ void initialize(const std::string& protocol_version,
+ const std::string& url,
+ const std::string& path,
+ const std::string& channel,
+ const std::string& version);
+
+ void setCheckPeriod(unsigned int seconds);
+
+ void startChecking(bool install_if_ready);
+ void stopChecking();
+ bool isChecking();
+
+ void setAppExitCallback(LLUpdaterService::app_exit_callback_t aecb) { mAppExitCallback = aecb;}
+
+ bool checkForInstall(bool launchInstaller); // Test if a local install is ready.
+ bool checkForResume(); // Test for resumeable d/l.
+
+ // LLUpdateChecker::Client:
+ virtual void error(std::string const & message);
+ virtual void optionalUpdate(std::string const & newVersion,
+ LLURI const & uri,
+ std::string const & hash);
+ virtual void requiredUpdate(std::string const & newVersion,
+ LLURI const & uri,
+ std::string const & hash);
+ virtual void upToDate(void);
+
+ // LLUpdateDownloader::Client
+ void downloadComplete(LLSD const & data);
+ void downloadError(std::string const & message);
+
+ bool onMainLoop(LLSD const & event);
+
+private:
+ void restartTimer(unsigned int seconds);
+ void stopTimer();
+};
+
+const std::string LLUpdaterServiceImpl::sListenerName = "LLUpdaterServiceImpl";
+
+LLUpdaterServiceImpl::LLUpdaterServiceImpl() :
+ mIsChecking(false),
+ mIsDownloading(false),
+ mCheckPeriod(0),
+ mUpdateChecker(*this),
+ mUpdateDownloader(*this)
+{
+}
+
+LLUpdaterServiceImpl::~LLUpdaterServiceImpl()
+{
+ LL_INFOS("UpdaterService") << "shutting down updater service" << LL_ENDL;
+ LLEventPumps::instance().obtain("mainloop").stopListening(sListenerName);
+}
+
+void LLUpdaterServiceImpl::initialize(const std::string& protocol_version,
+ const std::string& url,
+ const std::string& path,
+ const std::string& channel,
+ const std::string& version)
+{
+ if(mIsChecking || mIsDownloading)
+ {
+ throw LLUpdaterService::UsageError("LLUpdaterService::initialize call "
+ "while updater is running.");
+ }
+
+ mProtocolVersion = protocol_version;
+ mUrl = url;
+ mPath = path;
+ mChannel = channel;
+ mVersion = version;
+}
+
+void LLUpdaterServiceImpl::setCheckPeriod(unsigned int seconds)
+{
+ mCheckPeriod = seconds;
+}
+
+void LLUpdaterServiceImpl::startChecking(bool install_if_ready)
+{
+ if(mUrl.empty() || mChannel.empty() || mVersion.empty())
+ {
+ throw LLUpdaterService::UsageError("Set params before call to "
+ "LLUpdaterService::startCheck().");
+ }
+
+ mIsChecking = true;
+
+ // Check to see if an install is ready.
+ bool has_install = checkForInstall(install_if_ready);
+ if(!has_install)
+ {
+ checkForResume(); // will set mIsDownloading to true if resuming
+
+ if(!mIsDownloading)
+ {
+ // Checking can only occur during the mainloop.
+ // reset the timer to 0 so that the next mainloop event
+ // triggers a check;
+ restartTimer(0);
+ }
+ }
+}
+
+void LLUpdaterServiceImpl::stopChecking()
+{
+ if(mIsChecking)
+ {
+ mIsChecking = false;
+ stopTimer();
+ }
+
+ if(mIsDownloading)
+ {
+ mUpdateDownloader.cancel();
+ mIsDownloading = false;
+ }
+}
+
+bool LLUpdaterServiceImpl::isChecking()
+{
+ return mIsChecking;
+}
+
+bool LLUpdaterServiceImpl::checkForInstall(bool launchInstaller)
+{
+ bool foundInstall = false; // return true if install is found.
+
+ llifstream update_marker(update_marker_path(),
+ std::ios::in | std::ios::binary);
+
+ if(update_marker.is_open())
+ {
+ // Found an update info - now lets see if its valid.
+ LLSD update_info;
+ LLSDSerialize::fromXMLDocument(update_info, update_marker);
+ update_marker.close();
+
+ // Get the path to the installer file.
+ LLSD path = update_info.get("path");
+ if(update_info["current_version"].asString() != ll_get_version())
+ {
+ // This viewer is not the same version as the one that downloaded
+ // the update. Do not install this update.
+ if(!path.asString().empty())
+ {
+ llinfos << "ignoring update dowloaded by different client version" << llendl;
+ LLFile::remove(path.asString());
+ LLFile::remove(update_marker_path());
+ }
+ else
+ {
+ ; // Nothing to clean up.
+ }
+
+ foundInstall = false;
+ }
+ else if(path.isDefined() && !path.asString().empty())
+ {
+ if(launchInstaller)
+ {
+ LLFile::remove(update_marker_path());
+
+ int result = ll_install_update(install_script_path(),
+ update_info["path"].asString(),
+ install_script_mode());
+
+ if((result == 0) && mAppExitCallback)
+ {
+ mAppExitCallback();
+ } else if(result != 0) {
+ llwarns << "failed to run update install script" << LL_ENDL;
+ } else {
+ ; // No op.
+ }
+ }
+
+ foundInstall = true;
+ }
+ }
+ return foundInstall;
+}
+
+bool LLUpdaterServiceImpl::checkForResume()
+{
+ bool result = false;
+ std::string download_marker_path = mUpdateDownloader.downloadMarkerPath();
+ if(LLFile::isfile(download_marker_path))
+ {
+ llifstream download_marker_stream(download_marker_path,
+ std::ios::in | std::ios::binary);
+ if(download_marker_stream.is_open())
+ {
+ LLSD download_info;
+ LLSDSerialize::fromXMLDocument(download_info, download_marker_stream);
+ download_marker_stream.close();
+ if(download_info["current_version"].asString() == ll_get_version())
+ {
+ mIsDownloading = true;
+ mUpdateDownloader.resume();
+ result = true;
+ }
+ else
+ {
+ // The viewer that started this download is not the same as this viewer; ignore.
+ llinfos << "ignoring partial download from different viewer version" << llendl;
+ std::string path = download_info["path"].asString();
+ if(!path.empty()) LLFile::remove(path);
+ LLFile::remove(download_marker_path);
+ }
+ }
+ }
+ return result;
+}
+
+void LLUpdaterServiceImpl::error(std::string const & message)
+{
+ if(mIsChecking)
+ {
+ restartTimer(mCheckPeriod);
+ }
+}
+
+void LLUpdaterServiceImpl::optionalUpdate(std::string const & newVersion,
+ LLURI const & uri,
+ std::string const & hash)
+{
+ stopTimer();
+ mIsDownloading = true;
+ mUpdateDownloader.download(uri, hash);
+}
+
+void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion,
+ LLURI const & uri,
+ std::string const & hash)
+{
+ stopTimer();
+ mIsDownloading = true;
+ mUpdateDownloader.download(uri, hash);
+}
+
+void LLUpdaterServiceImpl::upToDate(void)
+{
+ if(mIsChecking)
+ {
+ restartTimer(mCheckPeriod);
+ }
+}
+
+void LLUpdaterServiceImpl::downloadComplete(LLSD const & data)
+{
+ mIsDownloading = false;
+
+ // Save out the download data to the SecondLifeUpdateReady
+ // marker file.
+ llofstream update_marker(update_marker_path());
+ LLSDSerialize::toPrettyXML(data, update_marker);
+
+ LLSD event;
+ event["pump"] = LLUpdaterService::pumpName();
+ LLSD payload;
+ payload["type"] = LLSD(LLUpdaterService::DOWNLOAD_COMPLETE);
+ event["payload"] = payload;
+ LLEventPumps::instance().obtain("mainlooprepeater").post(event);
+}
+
+void LLUpdaterServiceImpl::downloadError(std::string const & message)
+{
+ LL_INFOS("UpdaterService") << "Error downloading: " << message << LL_ENDL;
+
+ mIsDownloading = false;
+
+ // Restart the timer on error
+ if(mIsChecking)
+ {
+ restartTimer(mCheckPeriod);
+ }
+
+ LLSD event;
+ event["pump"] = LLUpdaterService::pumpName();
+ LLSD payload;
+ payload["type"] = LLSD(LLUpdaterService::DOWNLOAD_ERROR);
+ payload["message"] = message;
+ event["payload"] = payload;
+ LLEventPumps::instance().obtain("mainlooprepeater").post(event);
+}
+
+void LLUpdaterServiceImpl::restartTimer(unsigned int seconds)
+{
+ LL_INFOS("UpdaterService") << "will check for update again in " <<
+ seconds << " seconds" << LL_ENDL;
+ mTimer.start();
+ mTimer.setTimerExpirySec(seconds);
+ LLEventPumps::instance().obtain("mainloop").listen(
+ sListenerName, boost::bind(&LLUpdaterServiceImpl::onMainLoop, this, _1));
+}
+
+void LLUpdaterServiceImpl::stopTimer()
+{
+ mTimer.stop();
+ LLEventPumps::instance().obtain("mainloop").stopListening(sListenerName);
+}
+
+bool LLUpdaterServiceImpl::onMainLoop(LLSD const & event)
+{
+ if(mTimer.getStarted() && mTimer.hasExpired())
+ {
+ stopTimer();
+
+ // Check for failed install.
+ if(LLFile::isfile(ll_install_failed_marker_path()))
+ {
+ // TODO: notify the user.
+ llinfos << "found marker " << ll_install_failed_marker_path() << llendl;
+ llinfos << "last install attempt failed" << llendl;
+ LLFile::remove(ll_install_failed_marker_path());
+
+ LLSD event;
+ event["type"] = LLSD(LLUpdaterService::INSTALL_ERROR);
+ LLEventPumps::instance().obtain(LLUpdaterService::pumpName()).post(event);
+ }
+ else
+ {
+ mUpdateChecker.check(mProtocolVersion, mUrl, mPath, mChannel, mVersion);
+ }
+ }
+ else
+ {
+ // Keep on waiting...
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------
+// Facade interface
+
+std::string const & LLUpdaterService::pumpName(void)
+{
+ static std::string name("updater_service");
+ return name;
+}
+
+LLUpdaterService::LLUpdaterService()
+{
+ if(gUpdater.expired())
+ {
+ mImpl =
+ boost::shared_ptr<LLUpdaterServiceImpl>(new LLUpdaterServiceImpl());
+ gUpdater = mImpl;
+ }
+ else
+ {
+ mImpl = gUpdater.lock();
+ }
+}
+
+LLUpdaterService::~LLUpdaterService()
+{
+}
+
+void LLUpdaterService::initialize(const std::string& protocol_version,
+ const std::string& url,
+ const std::string& path,
+ const std::string& channel,
+ const std::string& version)
+{
+ mImpl->initialize(protocol_version, url, path, channel, version);
+}
+
+void LLUpdaterService::setCheckPeriod(unsigned int seconds)
+{
+ mImpl->setCheckPeriod(seconds);
+}
+
+void LLUpdaterService::startChecking(bool install_if_ready)
+{
+ mImpl->startChecking(install_if_ready);
+}
+
+void LLUpdaterService::stopChecking()
+{
+ mImpl->stopChecking();
+}
+
+bool LLUpdaterService::isChecking()
+{
+ return mImpl->isChecking();
+}
+
+void LLUpdaterService::setImplAppExitCallback(LLUpdaterService::app_exit_callback_t aecb)
+{
+ return mImpl->setAppExitCallback(aecb);
+}
+
+
+std::string const & ll_get_version(void) {
+ static std::string version("");
+
+ if (version.empty()) {
+ std::ostringstream stream;
+ stream << LL_VERSION_MAJOR << "."
+ << LL_VERSION_MINOR << "."
+ << LL_VERSION_PATCH << "."
+ << LL_VERSION_BUILD;
+ version = stream.str();
+ }
+
+ return version;
+}
+
diff --git a/indra/viewer_components/updater/llupdaterservice.h b/indra/viewer_components/updater/llupdaterservice.h
new file mode 100644
index 0000000000..752a6f834b
--- /dev/null
+++ b/indra/viewer_components/updater/llupdaterservice.h
@@ -0,0 +1,85 @@
+/**
+ * @file llupdaterservice.h
+ *
+ * $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_UPDATERSERVICE_H
+#define LL_UPDATERSERVICE_H
+
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+
+class LLUpdaterServiceImpl;
+
+class LLUpdaterService
+{
+public:
+ class UsageError: public std::runtime_error
+ {
+ public:
+ UsageError(const std::string& msg) : std::runtime_error(msg) {}
+ };
+
+ // Name of the event pump through which update events will be delivered.
+ static std::string const & pumpName(void);
+
+ // Type codes for events posted by this service. Stored the event's 'type' element.
+ enum eUpdateEvent {
+ INVALID,
+ DOWNLOAD_COMPLETE,
+ DOWNLOAD_ERROR,
+ INSTALL_ERROR
+ };
+
+ LLUpdaterService();
+ ~LLUpdaterService();
+
+ void initialize(const std::string& protocol_version,
+ const std::string& url,
+ const std::string& path,
+ const std::string& channel,
+ const std::string& version);
+
+ void setCheckPeriod(unsigned int seconds);
+
+ void startChecking(bool install_if_ready = false);
+ void stopChecking();
+ bool isChecking();
+
+ typedef boost::function<void (void)> app_exit_callback_t;
+ template <typename F>
+ void setAppExitCallback(F const &callable)
+ {
+ app_exit_callback_t aecb = callable;
+ setImplAppExitCallback(aecb);
+ }
+
+private:
+ boost::shared_ptr<LLUpdaterServiceImpl> mImpl;
+ void setImplAppExitCallback(app_exit_callback_t aecb);
+};
+
+// Returns the full version as a string.
+std::string const & ll_get_version(void);
+
+#endif // LL_UPDATERSERVICE_H
diff --git a/indra/viewer_components/updater/scripts/darwin/update_install b/indra/viewer_components/updater/scripts/darwin/update_install
new file mode 100644
index 0000000000..b174b3570a
--- /dev/null
+++ b/indra/viewer_components/updater/scripts/darwin/update_install
@@ -0,0 +1,9 @@
+#! /bin/bash
+
+#
+# The first argument contains the path to the installer app. The second a path
+# to a marker file which should be created if the installer fails.q
+#
+
+open ../Resources/mac-updater.app --args -dmg "$1" -name "Second Life Viewer 2" -marker "$2"
+exit 0
diff --git a/indra/viewer_components/updater/scripts/linux/update_install b/indra/viewer_components/updater/scripts/linux/update_install
new file mode 100644
index 0000000000..fef5ef7d09
--- /dev/null
+++ b/indra/viewer_components/updater/scripts/linux/update_install
@@ -0,0 +1,10 @@
+#! /bin/bash
+INSTALL_DIR=$(cd "$(dirname $0)/.." ; pwd)
+export LD_LIBRARY_PATH=$INSTALL_DIR/lib
+bin/linux-updater.bin --file "$1" --dest "$INSTALL_DIR" --name "Second Life Viewer 2" --stringsdir "$INSTALL_DIR/skins/default/xui/en" --stringsfile "strings.xml"
+
+if [ $? -ne 0 ]
+ then touch $2
+fi
+
+rm -f $1
diff --git a/indra/viewer_components/updater/scripts/windows/update_install.bat b/indra/viewer_components/updater/scripts/windows/update_install.bat
new file mode 100644
index 0000000000..42e148a707
--- /dev/null
+++ b/indra/viewer_components/updater/scripts/windows/update_install.bat
@@ -0,0 +1,3 @@
+start /WAIT %1 /SKIP_DIALOGS
+IF ERRORLEVEL 1 ECHO %ERRORLEVEL% > %2
+DEL %1
diff --git a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp
new file mode 100644
index 0000000000..04ed4e6364
--- /dev/null
+++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp
@@ -0,0 +1,199 @@
+/**
+ * @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 &){}
+
+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) {}
+
+int ll_install_update(std::string const &, std::string const &, 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());
+ }
+}
diff --git a/scripts/md5check.py b/scripts/md5check.py
index 951fe0105c..951fe0105c 100644..100755
--- a/scripts/md5check.py
+++ b/scripts/md5check.py