Pull merge from lindenlab/viewer-release
commit
ce5baf14ac
2
.hgtags
2
.hgtags
|
|
@ -467,3 +467,5 @@ fe4f7c5e9fd27e09d03deb1cc9ab3e5093f6309e 3.6.3-release
|
||||||
bf6d453046011a11de2643fac610cc5258650f82 3.6.5-release
|
bf6d453046011a11de2643fac610cc5258650f82 3.6.5-release
|
||||||
ae457ece77001767ae9613148c495e7b98cc0f4a 3.6.7-release
|
ae457ece77001767ae9613148c495e7b98cc0f4a 3.6.7-release
|
||||||
d40c66e410741de7e90b1ed6dac28dd8a2d7e1f6 3.6.8-release
|
d40c66e410741de7e90b1ed6dac28dd8a2d7e1f6 3.6.8-release
|
||||||
|
70eda3721d36df3e00730629c42a1304e5bc65b8 3.6.9-release
|
||||||
|
5b54b36862ff8bc3b6935673c9d1c1f22ee8d521 3.6.10-release
|
||||||
|
|
|
||||||
15
BuildParams
15
BuildParams
|
|
@ -27,9 +27,6 @@ Linux.distcc_version =
|
||||||
Linux.gcc_version = /usr/bin/gcc-4.6
|
Linux.gcc_version = /usr/bin/gcc-4.6
|
||||||
Linux.cxx_version = /usr/bin/g++-4.6
|
Linux.cxx_version = /usr/bin/g++-4.6
|
||||||
|
|
||||||
# Setup default sourceid so Windows can pick up the TeamCity override
|
|
||||||
sourceid = ""
|
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
#### Examples of how to set the viewer_channel ####
|
#### Examples of how to set the viewer_channel ####
|
||||||
#
|
#
|
||||||
|
|
@ -50,6 +47,18 @@ sourceid = ""
|
||||||
################################################################
|
################################################################
|
||||||
viewer_channel = "Second Life Test"
|
viewer_channel = "Second Life Test"
|
||||||
|
|
||||||
|
# Setup default packaging parameters.
|
||||||
|
sourceid = ""
|
||||||
|
additional_packages = "Amazon Desura B C"
|
||||||
|
Amazon_sourceid = "1207v_Amazon"
|
||||||
|
Amazon_viewer_channel_suffix = " Amazon"
|
||||||
|
Desura_sourceid = "1208_desura"
|
||||||
|
Desura_viewer_channel_suffix = " Desura"
|
||||||
|
B_sourceid = "1301_B"
|
||||||
|
B_viewer_channel_suffix = " B"
|
||||||
|
C_sourceid = "1302_C"
|
||||||
|
C_viewer_channel_suffix = " C"
|
||||||
|
|
||||||
# Report changes since...
|
# Report changes since...
|
||||||
viewer-development.show_changes_since = last_sprint
|
viewer-development.show_changes_since = last_sprint
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1965,11 +1965,11 @@
|
||||||
<key>package_description</key>
|
<key>package_description</key>
|
||||||
<map>
|
<map>
|
||||||
<key>description</key>
|
<key>description</key>
|
||||||
<string>Spell checking dictionaries</string>
|
<string>Second Life Viewer</string>
|
||||||
<key>license</key>
|
<key>license</key>
|
||||||
<string>various open</string>
|
<string>LGPL</string>
|
||||||
<key>name</key>
|
<key>name</key>
|
||||||
<string>dictionaries</string>
|
<string>Second Life Viewer</string>
|
||||||
<key>platforms</key>
|
<key>platforms</key>
|
||||||
<map>
|
<map>
|
||||||
<key>common</key>
|
<key>common</key>
|
||||||
|
|
|
||||||
28
build.sh
28
build.sh
|
|
@ -38,22 +38,22 @@ build_dir_CYGWIN()
|
||||||
|
|
||||||
installer_Darwin()
|
installer_Darwin()
|
||||||
{
|
{
|
||||||
ls -1td "$(build_dir_Darwin ${last_built_variant:-Release})/newview/"*.dmg 2>/dev/null | sed 1q
|
ls -1tr "$(build_dir_Darwin ${last_built_variant:-Release})/newview/"*"$additional_package_name"*.dmg 2>/dev/null | sed 1q
|
||||||
}
|
}
|
||||||
|
|
||||||
installer_Linux()
|
installer_Linux()
|
||||||
{
|
{
|
||||||
ls -1td "$(build_dir_Linux ${last_built_variant:-Release})/newview/"*.tar.bz2 2>/dev/null | sed 1q
|
ls -1tr "$(build_dir_Linux ${last_built_variant:-Release})/newview/"*"$additional_package_name"*.tar.bz2 2>/dev/null | grep -v symbols | sed 1q
|
||||||
}
|
}
|
||||||
|
|
||||||
installer_CYGWIN()
|
installer_CYGWIN()
|
||||||
{
|
{
|
||||||
v=${last_built_variant:-Release}
|
v=${last_built_variant:-Release}
|
||||||
d=$(build_dir_CYGWIN $v)
|
d=$(build_dir_CYGWIN $v)
|
||||||
if [ -r "$d/newview/$v/touched.bat" ]
|
if [ -r "$d/newview/$additional_package_name$v/touched.bat" ]
|
||||||
then
|
then
|
||||||
p=$(sed 's:.*=::' "$d/newview/$v/touched.bat")
|
p=$(sed 's:.*=::' "$d/newview/$additional_package_name$v/touched.bat")
|
||||||
echo "$d/newview/$v/$p"
|
echo "$d/newview/$additional_package_name$v/$p"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -355,10 +355,28 @@ then
|
||||||
# Coverity doesn't package, so it's ok, anything else is fail
|
# Coverity doesn't package, so it's ok, anything else is fail
|
||||||
succeeded=$build_coverity
|
succeeded=$build_coverity
|
||||||
else
|
else
|
||||||
|
# Upload base package.
|
||||||
upload_item installer "$package" binary/octet-stream
|
upload_item installer "$package" binary/octet-stream
|
||||||
upload_item quicklink "$package" binary/octet-stream
|
upload_item quicklink "$package" binary/octet-stream
|
||||||
[ -f $build_dir/summary.json ] && upload_item installer $build_dir/summary.json text/plain
|
[ -f $build_dir/summary.json ] && upload_item installer $build_dir/summary.json text/plain
|
||||||
|
|
||||||
|
# Upload additional packages.
|
||||||
|
for package_id in $additional_packages
|
||||||
|
do
|
||||||
|
case $arch in
|
||||||
|
CYGWIN) export additional_package_name="$package_id/" ;;
|
||||||
|
*) export additional_package_name=$package_id ;;
|
||||||
|
esac
|
||||||
|
package=$(installer_$arch)
|
||||||
|
if [ x"$package" != x ]
|
||||||
|
then
|
||||||
|
upload_item installer "$package" binary/octet-stream
|
||||||
|
else
|
||||||
|
record_failure "Failed to upload $package_id package."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
export additional_package_name=""
|
||||||
|
|
||||||
case "$last_built_variant" in
|
case "$last_built_variant" in
|
||||||
Release)
|
Release)
|
||||||
# Upload crash reporter files
|
# Upload crash reporter files
|
||||||
|
|
|
||||||
|
|
@ -175,8 +175,11 @@ Ansariel Hiller
|
||||||
STORM-1685
|
STORM-1685
|
||||||
STORM-1713
|
STORM-1713
|
||||||
STORM-1899
|
STORM-1899
|
||||||
|
STORM-1932
|
||||||
|
STORM-1933
|
||||||
MAINT-2368
|
MAINT-2368
|
||||||
STORM-1931
|
STORM-1931
|
||||||
|
MAINT-2773
|
||||||
Aralara Rajal
|
Aralara Rajal
|
||||||
Arare Chantilly
|
Arare Chantilly
|
||||||
CHUIBUG-191
|
CHUIBUG-191
|
||||||
|
|
@ -304,9 +307,13 @@ Christopher Organiser
|
||||||
Ciaran Laval
|
Ciaran Laval
|
||||||
Cinder Roxley
|
Cinder Roxley
|
||||||
BUG-2326
|
BUG-2326
|
||||||
|
OPEN-185
|
||||||
STORM-1703
|
STORM-1703
|
||||||
STORM-1948
|
STORM-1948
|
||||||
|
STORM-1888
|
||||||
|
STORM-1958
|
||||||
STORM-1952
|
STORM-1952
|
||||||
|
STORM-1951
|
||||||
Clara Young
|
Clara Young
|
||||||
Coaldust Numbers
|
Coaldust Numbers
|
||||||
VWR-1095
|
VWR-1095
|
||||||
|
|
@ -652,7 +659,7 @@ Jonathan Yap
|
||||||
STORM-1809
|
STORM-1809
|
||||||
STORM-1793
|
STORM-1793
|
||||||
STORM-1810
|
STORM-1810
|
||||||
STORM-1877
|
STORM-1838
|
||||||
STORM-1892
|
STORM-1892
|
||||||
STORM-1894
|
STORM-1894
|
||||||
STORM-1860
|
STORM-1860
|
||||||
|
|
@ -662,8 +669,11 @@ Jonathan Yap
|
||||||
STORM-1858
|
STORM-1858
|
||||||
STORM-1862
|
STORM-1862
|
||||||
STORM-1918
|
STORM-1918
|
||||||
|
STORM-1929
|
||||||
STORM-1953
|
STORM-1953
|
||||||
OPEN-161
|
OPEN-161
|
||||||
|
STORM-1953
|
||||||
|
STORM-1957
|
||||||
Kadah Coba
|
Kadah Coba
|
||||||
STORM-1060
|
STORM-1060
|
||||||
STORM-1843
|
STORM-1843
|
||||||
|
|
@ -679,7 +689,9 @@ Kagehi Kohn
|
||||||
Kaimen Takahe
|
Kaimen Takahe
|
||||||
Katharine Berry
|
Katharine Berry
|
||||||
STORM-1900
|
STORM-1900
|
||||||
|
OPEN-149
|
||||||
STORM-1940
|
STORM-1940
|
||||||
|
OPEN-149
|
||||||
STORM-1941
|
STORM-1941
|
||||||
Keklily Longfall
|
Keklily Longfall
|
||||||
Ken Lavender
|
Ken Lavender
|
||||||
|
|
@ -928,7 +940,9 @@ Nicky Dasmijn
|
||||||
STORM-1936
|
STORM-1936
|
||||||
BUG-3605
|
BUG-3605
|
||||||
CHUIBUG-197
|
CHUIBUG-197
|
||||||
|
OPEN-187
|
||||||
STORM-1937
|
STORM-1937
|
||||||
|
OPEN-187
|
||||||
Nicky Perian
|
Nicky Perian
|
||||||
OPEN-1
|
OPEN-1
|
||||||
STORM-1087
|
STORM-1087
|
||||||
|
|
@ -1125,6 +1139,7 @@ Slee Mayo
|
||||||
snowy Sidran
|
snowy Sidran
|
||||||
Sovereign Engineer
|
Sovereign Engineer
|
||||||
MAINT-2334
|
MAINT-2334
|
||||||
|
OPEN-189
|
||||||
SpacedOut Frye
|
SpacedOut Frye
|
||||||
VWR-34
|
VWR-34
|
||||||
VWR-45
|
VWR-45
|
||||||
|
|
@ -1293,6 +1308,7 @@ Westley Streeter
|
||||||
Whimsy Winx
|
Whimsy Winx
|
||||||
Whirly Fizzle
|
Whirly Fizzle
|
||||||
STORM-1895
|
STORM-1895
|
||||||
|
VWR-29543
|
||||||
MAINT-873
|
MAINT-873
|
||||||
STORM-1930
|
STORM-1930
|
||||||
Whoops Babii
|
Whoops Babii
|
||||||
|
|
@ -1356,6 +1372,7 @@ YongYong Francois
|
||||||
Zak Westminster
|
Zak Westminster
|
||||||
Zai Lynch
|
Zai Lynch
|
||||||
VWR-19505
|
VWR-19505
|
||||||
|
STORM-1902
|
||||||
Zana Kohime
|
Zana Kohime
|
||||||
Zaren Alexander
|
Zaren Alexander
|
||||||
Zarkonnen Decosta
|
Zarkonnen Decosta
|
||||||
|
|
|
||||||
|
|
@ -63,10 +63,11 @@ add_subdirectory(${VIEWER_PREFIX}test)
|
||||||
# viewer media plugins
|
# viewer media plugins
|
||||||
add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins)
|
add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins)
|
||||||
|
|
||||||
# llplugin testbed code (is this the right way to include it?)
|
# llplugin testbed code (is this the right way to include it?)
|
||||||
if (LL_TESTS AND NOT LINUX)
|
if (LL_TESTS AND NOT LINUX)
|
||||||
add_subdirectory(${VIEWER_PREFIX}test_apps/llplugintest)
|
add_subdirectory(${VIEWER_PREFIX}test_apps/llplugintest)
|
||||||
endif (LL_TESTS AND NOT LINUX)
|
add_subdirectory(${VIEWER_PREFIX}test_apps/llfbconnecttest)
|
||||||
|
endif (LL_TESTS AND NOT LINUX)
|
||||||
|
|
||||||
if (LINUX)
|
if (LINUX)
|
||||||
add_subdirectory(${VIEWER_PREFIX}linux_crash_logger)
|
add_subdirectory(${VIEWER_PREFIX}linux_crash_logger)
|
||||||
|
|
|
||||||
|
|
@ -16,22 +16,26 @@ if (NOT DEFINED VIEWER_SHORT_VERSION) # will be true in indra/, false in indra/n
|
||||||
|
|
||||||
else (DEFINED ENV{revision})
|
else (DEFINED ENV{revision})
|
||||||
find_program(MERCURIAL hg)
|
find_program(MERCURIAL hg)
|
||||||
if (DEFINED MERCURIAL)
|
find_program(WORDCOUNT wc)
|
||||||
|
find_program(SED sed)
|
||||||
|
if (DEFINED MERCURIAL AND DEFINED WORDCOUNT AND DEFINED SED)
|
||||||
execute_process(
|
execute_process(
|
||||||
COMMAND ${MERCURIAL} log -r tip --template "{rev}"
|
COMMAND ${MERCURIAL} log -r tip:0 --template '\\n'
|
||||||
|
COMMAND ${WORDCOUNT} -l
|
||||||
|
COMMAND ${SED} "s/ //g"
|
||||||
OUTPUT_VARIABLE VIEWER_VERSION_REVISION
|
OUTPUT_VARIABLE VIEWER_VERSION_REVISION
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
)
|
)
|
||||||
if ("${VIEWER_VERSION_REVISION}" MATCHES "^[0-9]+$")
|
if ("${VIEWER_VERSION_REVISION}" MATCHES "^[0-9]+$")
|
||||||
message("Revision (from hg) ${VIEWER_VERSION_REVISION}")
|
message("Revision (from hg) ${VIEWER_VERSION_REVISION}")
|
||||||
else ("${VIEWER_VERSION_REVISION}" MATCHES "^[0-9]+$")
|
else ("${VIEWER_VERSION_REVISION}" MATCHES "^[0-9]+$")
|
||||||
|
message("Revision not set (repository not found?); using 0")
|
||||||
set(VIEWER_VERSION_REVISION 0 )
|
set(VIEWER_VERSION_REVISION 0 )
|
||||||
message("Revision not set, repository not found, using ${VIEWER_VERSION_REVISION}")
|
|
||||||
endif ("${VIEWER_VERSION_REVISION}" MATCHES "^[0-9]+$")
|
endif ("${VIEWER_VERSION_REVISION}" MATCHES "^[0-9]+$")
|
||||||
else (DEFINED MERCURIAL)
|
else (DEFINED MERCURIAL AND DEFINED WORDCOUNT AND DEFINED SED)
|
||||||
|
message("Revision not set: 'hg', 'wc' or 'sed' not found; using 0")
|
||||||
set(VIEWER_VERSION_REVISION 0)
|
set(VIEWER_VERSION_REVISION 0)
|
||||||
message("Revision not set, 'hg' not found (${MERCURIAL}), using ${VIEWER_VERSION_REVISION}")
|
endif (DEFINED MERCURIAL AND DEFINED WORDCOUNT AND DEFINED SED)
|
||||||
endif (DEFINED MERCURIAL)
|
|
||||||
endif (DEFINED ENV{revision})
|
endif (DEFINED ENV{revision})
|
||||||
message("Building '${VIEWER_CHANNEL}' Version ${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}")
|
message("Building '${VIEWER_CHANNEL}' Version ${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}")
|
||||||
else ( EXISTS ${VIEWER_VERSION_BASE_FILE} )
|
else ( EXISTS ${VIEWER_VERSION_BASE_FILE} )
|
||||||
|
|
|
||||||
|
|
@ -224,15 +224,98 @@ def main():
|
||||||
for opt in args:
|
for opt in args:
|
||||||
print "Option:", opt, "=", args[opt]
|
print "Option:", opt, "=", args[opt]
|
||||||
|
|
||||||
|
# pass in sourceid as an argument now instead of an environment variable
|
||||||
|
try:
|
||||||
|
args['sourceid'] = os.environ["sourceid"]
|
||||||
|
except KeyError:
|
||||||
|
args['sourceid'] = ""
|
||||||
|
|
||||||
|
# Build base package.
|
||||||
|
touch = args.get('touch')
|
||||||
|
if touch:
|
||||||
|
print 'Creating base package'
|
||||||
|
args['package_id'] = "" # base package has no package ID
|
||||||
wm = LLManifest.for_platform(args['platform'], args.get('arch'))(args)
|
wm = LLManifest.for_platform(args['platform'], args.get('arch'))(args)
|
||||||
wm.do(*args['actions'])
|
wm.do(*args['actions'])
|
||||||
|
# Store package file for later if making touched file.
|
||||||
|
base_package_file = ""
|
||||||
|
if touch:
|
||||||
|
print 'Created base package ', wm.package_file
|
||||||
|
base_package_file = "" + wm.package_file
|
||||||
|
|
||||||
|
# handle multiple packages if set
|
||||||
|
try:
|
||||||
|
additional_packages = os.environ["additional_packages"]
|
||||||
|
except KeyError:
|
||||||
|
additional_packages = ""
|
||||||
|
if additional_packages:
|
||||||
|
# Determine destination prefix / suffix for additional packages.
|
||||||
|
base_dest_postfix = args['dest']
|
||||||
|
base_dest_prefix = ""
|
||||||
|
base_dest_parts = args['dest'].split(os.sep)
|
||||||
|
if len(base_dest_parts) > 1:
|
||||||
|
base_dest_postfix = base_dest_parts[len(base_dest_parts) - 1]
|
||||||
|
base_dest_prefix = base_dest_parts[0]
|
||||||
|
i = 1
|
||||||
|
while i < len(base_dest_parts) - 1:
|
||||||
|
base_dest_prefix = base_dest_prefix + os.sep + base_dest_parts[i]
|
||||||
|
i = i + 1
|
||||||
|
# Determine touched prefix / suffix for additional packages.
|
||||||
|
base_touch_postfix = ""
|
||||||
|
base_touch_prefix = ""
|
||||||
|
if touch:
|
||||||
|
base_touch_postfix = touch
|
||||||
|
base_touch_parts = touch.split('/')
|
||||||
|
if "arwin" in args['platform']:
|
||||||
|
if len(base_touch_parts) > 1:
|
||||||
|
base_touch_postfix = base_touch_parts[len(base_touch_parts) - 1]
|
||||||
|
base_touch_prefix = base_touch_parts[0]
|
||||||
|
i = 1
|
||||||
|
while i < len(base_touch_parts) - 1:
|
||||||
|
base_touch_prefix = base_touch_prefix + '/' + base_touch_parts[i]
|
||||||
|
i = i + 1
|
||||||
|
else:
|
||||||
|
if len(base_touch_parts) > 2:
|
||||||
|
base_touch_postfix = base_touch_parts[len(base_touch_parts) - 2] + '/' + base_touch_parts[len(base_touch_parts) - 1]
|
||||||
|
base_touch_prefix = base_touch_parts[0]
|
||||||
|
i = 1
|
||||||
|
while i < len(base_touch_parts) - 2:
|
||||||
|
base_touch_prefix = base_touch_prefix + '/' + base_touch_parts[i]
|
||||||
|
i = i + 1
|
||||||
|
# Store base channel name.
|
||||||
|
base_channel_name = args['channel']
|
||||||
|
# Build each additional package.
|
||||||
|
package_id_list = additional_packages.split(" ")
|
||||||
|
for package_id in package_id_list:
|
||||||
|
try:
|
||||||
|
args['package_id'] = package_id
|
||||||
|
args['channel'] = base_channel_name + os.environ[package_id + "_viewer_channel_suffix"]
|
||||||
|
if package_id + "_sourceid" in os.environ:
|
||||||
|
args['sourceid'] = os.environ[package_id + "_sourceid"]
|
||||||
|
else:
|
||||||
|
args['sourceid'] = ""
|
||||||
|
args['dest'] = base_dest_prefix + os.sep + package_id + os.sep + base_dest_postfix
|
||||||
|
except KeyError:
|
||||||
|
sys.stderr.write("Failed to create package for package_id: %s" % package_id)
|
||||||
|
sys.stderr.flush()
|
||||||
|
continue
|
||||||
|
if touch:
|
||||||
|
print 'Creating additional package for ', package_id, ' in ', args['dest']
|
||||||
|
wm = LLManifest.for_platform(args['platform'], args.get('arch'))(args)
|
||||||
|
wm.do(*args['actions'])
|
||||||
|
if touch:
|
||||||
|
print 'Created additional package ', wm.package_file, ' for ', package_id
|
||||||
|
faketouch = base_touch_prefix + '/' + package_id + '/' + base_touch_postfix
|
||||||
|
fp = open(faketouch, 'w')
|
||||||
|
fp.write('set package_file=%s\n' % wm.package_file)
|
||||||
|
fp.close()
|
||||||
|
|
||||||
# Write out the package file in this format, so that it can easily be called
|
# Write out the package file in this format, so that it can easily be called
|
||||||
# and used in a .bat file - yeah, it sucks, but this is the simplest...
|
# and used in a .bat file - yeah, it sucks, but this is the simplest...
|
||||||
touch = args.get('touch')
|
touch = args.get('touch')
|
||||||
if touch:
|
if touch:
|
||||||
fp = open(touch, 'w')
|
fp = open(touch, 'w')
|
||||||
fp.write('set package_file=%s\n' % wm.package_file)
|
fp.write('set package_file=%s\n' % base_package_file)
|
||||||
fp.close()
|
fp.close()
|
||||||
print 'touched', touch
|
print 'touched', touch
|
||||||
return 0
|
return 0
|
||||||
|
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
/**
|
|
||||||
* @file llversionviewer.h
|
|
||||||
* @brief
|
|
||||||
*
|
|
||||||
* $LicenseInfo:firstyear=2002&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_LLVERSIONVIEWER_H
|
|
||||||
#define LL_LLVERSIONVIEWER_H
|
|
||||||
|
|
||||||
const S32 LL_VERSION_MAJOR = 3;
|
|
||||||
const S32 LL_VERSION_MINOR = 4;
|
|
||||||
const S32 LL_VERSION_PATCH = 6;
|
|
||||||
const S32 LL_VERSION_BUILD = 0;
|
|
||||||
|
|
||||||
const char * const LL_CHANNEL = "Second Life Developer";
|
|
||||||
|
|
||||||
#if LL_DARWIN
|
|
||||||
const char * const LL_VERSION_BUNDLE_ID = "com.secondlife.indra.viewer";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -50,7 +50,7 @@ class LLColor4
|
||||||
LLColor4(F32 r, F32 g, F32 b); // Initializes LLColor4 to (r, g, b, 1)
|
LLColor4(F32 r, F32 g, F32 b); // Initializes LLColor4 to (r, g, b, 1)
|
||||||
LLColor4(F32 r, F32 g, F32 b, F32 a); // Initializes LLColor4 to (r. g, b, a)
|
LLColor4(F32 r, F32 g, F32 b, F32 a); // Initializes LLColor4 to (r. g, b, a)
|
||||||
LLColor4(U32 clr); // Initializes LLColor4 to (r=clr>>24, etc))
|
LLColor4(U32 clr); // Initializes LLColor4 to (r=clr>>24, etc))
|
||||||
LLColor4(const F32 *vec); // Initializes LLColor4 to (vec[0]. vec[1], vec[2], 1)
|
LLColor4(const F32 *vec); // Initializes LLColor4 to (vec[0]. vec[1], vec[2], vec[3])
|
||||||
LLColor4(const LLColor3 &vec, F32 a = 1.f); // Initializes LLColor4 to (vec, a)
|
LLColor4(const LLColor3 &vec, F32 a = 1.f); // Initializes LLColor4 to (vec, a)
|
||||||
explicit LLColor4(const LLSD& sd);
|
explicit LLColor4(const LLSD& sd);
|
||||||
explicit LLColor4(const LLColor4U& color4u); // "explicit" to avoid automatic conversion
|
explicit LLColor4(const LLColor4U& color4u); // "explicit" to avoid automatic conversion
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,8 @@ static void request(
|
||||||
Injector* body_injector,
|
Injector* body_injector,
|
||||||
LLCurl::ResponderPtr responder,
|
LLCurl::ResponderPtr responder,
|
||||||
const F32 timeout = HTTP_REQUEST_EXPIRY_SECS,
|
const F32 timeout = HTTP_REQUEST_EXPIRY_SECS,
|
||||||
const LLSD& headers = LLSD()
|
const LLSD& headers = LLSD(),
|
||||||
|
bool follow_redirects = true
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (!LLHTTPClient::hasPump())
|
if (!LLHTTPClient::hasPump())
|
||||||
|
|
@ -231,7 +232,7 @@ static void request(
|
||||||
}
|
}
|
||||||
LLPumpIO::chain_t chain;
|
LLPumpIO::chain_t chain;
|
||||||
|
|
||||||
LLURLRequest* req = new LLURLRequest(method, url);
|
LLURLRequest* req = new LLURLRequest(method, url, follow_redirects);
|
||||||
if(!req->isValid())//failed
|
if(!req->isValid())//failed
|
||||||
{
|
{
|
||||||
if (responder)
|
if (responder)
|
||||||
|
|
@ -334,7 +335,8 @@ void LLHTTPClient::getByteRange(
|
||||||
S32 bytes,
|
S32 bytes,
|
||||||
ResponderPtr responder,
|
ResponderPtr responder,
|
||||||
const LLSD& hdrs,
|
const LLSD& hdrs,
|
||||||
const F32 timeout)
|
const F32 timeout,
|
||||||
|
bool follow_redirects /* = true */)
|
||||||
{
|
{
|
||||||
LLSD headers = hdrs;
|
LLSD headers = hdrs;
|
||||||
if(offset > 0 || bytes > 0)
|
if(offset > 0 || bytes > 0)
|
||||||
|
|
@ -342,37 +344,42 @@ void LLHTTPClient::getByteRange(
|
||||||
std::string range = llformat("bytes=%d-%d", offset, offset+bytes-1);
|
std::string range = llformat("bytes=%d-%d", offset, offset+bytes-1);
|
||||||
headers["Range"] = range;
|
headers["Range"] = range;
|
||||||
}
|
}
|
||||||
request(url,LLURLRequest::HTTP_GET, NULL, responder, timeout, headers);
|
request(url,LLURLRequest::HTTP_GET, NULL, responder, timeout, headers, follow_redirects);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLHTTPClient::head(
|
void LLHTTPClient::head(
|
||||||
const std::string& url,
|
const std::string& url,
|
||||||
ResponderPtr responder,
|
ResponderPtr responder,
|
||||||
const LLSD& headers,
|
const LLSD& headers,
|
||||||
const F32 timeout)
|
const F32 timeout,
|
||||||
|
bool follow_redirects /* = true */)
|
||||||
{
|
{
|
||||||
request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers);
|
request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLHTTPClient::get(const std::string& url, ResponderPtr responder, const LLSD& headers, const F32 timeout)
|
void LLHTTPClient::get(const std::string& url, ResponderPtr responder, const LLSD& headers, const F32 timeout,
|
||||||
|
bool follow_redirects /* = true */)
|
||||||
{
|
{
|
||||||
request(url, LLURLRequest::HTTP_GET, NULL, responder, timeout, headers);
|
request(url, LLURLRequest::HTTP_GET, NULL, responder, timeout, headers, follow_redirects);
|
||||||
}
|
}
|
||||||
void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const LLSD& headers, const F32 timeout)
|
void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const LLSD& headers,
|
||||||
|
const F32 timeout, bool follow_redirects /* = true */)
|
||||||
{
|
{
|
||||||
request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers);
|
request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects);
|
||||||
}
|
}
|
||||||
void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const F32 timeout)
|
void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const F32 timeout,
|
||||||
|
bool follow_redirects /* = true */)
|
||||||
{
|
{
|
||||||
getHeaderOnly(url, responder, LLSD(), timeout);
|
getHeaderOnly(url, responder, LLSD(), timeout, follow_redirects);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLHTTPClient::get(const std::string& url, const LLSD& query, ResponderPtr responder, const LLSD& headers, const F32 timeout)
|
void LLHTTPClient::get(const std::string& url, const LLSD& query, ResponderPtr responder, const LLSD& headers,
|
||||||
|
const F32 timeout, bool follow_redirects /* = true */)
|
||||||
{
|
{
|
||||||
LLURI uri;
|
LLURI uri;
|
||||||
|
|
||||||
uri = LLURI::buildHTTP(url, LLSD::emptyArray(), query);
|
uri = LLURI::buildHTTP(url, LLSD::emptyArray(), query);
|
||||||
get(uri.asString(), responder, headers, timeout);
|
get(uri.asString(), responder, headers, timeout, follow_redirects);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A simple class for managing data returned from a curl http request.
|
// A simple class for managing data returned from a curl http request.
|
||||||
|
|
|
||||||
|
|
@ -63,10 +63,15 @@ public:
|
||||||
const std::string& url,
|
const std::string& url,
|
||||||
ResponderPtr,
|
ResponderPtr,
|
||||||
const LLSD& headers = LLSD(),
|
const LLSD& headers = LLSD(),
|
||||||
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
|
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS,
|
||||||
static void getByteRange(const std::string& url, S32 offset, S32 bytes, ResponderPtr, const LLSD& headers=LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
|
bool follow_redirects = true);
|
||||||
static void get(const std::string& url, ResponderPtr, const LLSD& headers = LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
|
static void getByteRange(const std::string& url, S32 offset, S32 bytes, ResponderPtr,
|
||||||
static void get(const std::string& url, const LLSD& query, ResponderPtr, const LLSD& headers = LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
|
const LLSD& headers=LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS,
|
||||||
|
bool follow_redirects = true);
|
||||||
|
static void get(const std::string& url, ResponderPtr, const LLSD& headers = LLSD(),
|
||||||
|
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS, bool follow_redirects = true);
|
||||||
|
static void get(const std::string& url, const LLSD& query, ResponderPtr, const LLSD& headers = LLSD(),
|
||||||
|
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS, bool follow_redirects = true);
|
||||||
|
|
||||||
static void put(
|
static void put(
|
||||||
const std::string& url,
|
const std::string& url,
|
||||||
|
|
@ -74,8 +79,10 @@ public:
|
||||||
ResponderPtr,
|
ResponderPtr,
|
||||||
const LLSD& headers = LLSD(),
|
const LLSD& headers = LLSD(),
|
||||||
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
|
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
|
||||||
static void getHeaderOnly(const std::string& url, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
|
static void getHeaderOnly(const std::string& url, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS,
|
||||||
static void getHeaderOnly(const std::string& url, ResponderPtr, const LLSD& headers, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
|
bool follow_redirects = true);
|
||||||
|
static void getHeaderOnly(const std::string& url, ResponderPtr, const LLSD& headers,
|
||||||
|
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS, bool follow_redirects = true);
|
||||||
|
|
||||||
static void post(
|
static void post(
|
||||||
const std::string& url,
|
const std::string& url,
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ enum EInstantMessage
|
||||||
IM_LURE_ACCEPTED = 23,
|
IM_LURE_ACCEPTED = 23,
|
||||||
IM_LURE_DECLINED = 24,
|
IM_LURE_DECLINED = 24,
|
||||||
IM_GODLIKE_LURE_USER = 25,
|
IM_GODLIKE_LURE_USER = 25,
|
||||||
IM_YET_TO_BE_USED = 26,
|
IM_TELEPORT_REQUEST = 26,
|
||||||
|
|
||||||
// IM that notifie of a new group election.
|
// IM that notifie of a new group election.
|
||||||
// Name is name of person who called vote.
|
// Name is name of person who called vote.
|
||||||
|
|
|
||||||
|
|
@ -150,16 +150,19 @@ std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action)
|
||||||
return VERBS[action];
|
return VERBS[action];
|
||||||
}
|
}
|
||||||
|
|
||||||
LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action) :
|
LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, bool follow_redirects /* = true */) :
|
||||||
mAction(action)
|
mAction(action),
|
||||||
|
mFollowRedirects(follow_redirects)
|
||||||
{
|
{
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
LLURLRequest::LLURLRequest(
|
LLURLRequest::LLURLRequest(
|
||||||
LLURLRequest::ERequestAction action,
|
LLURLRequest::ERequestAction action,
|
||||||
const std::string& url) :
|
const std::string& url,
|
||||||
mAction(action)
|
bool follow_redirects /* = true */) :
|
||||||
|
mAction(action),
|
||||||
|
mFollowRedirects(follow_redirects)
|
||||||
{
|
{
|
||||||
initialize();
|
initialize();
|
||||||
setURL(url);
|
setURL(url);
|
||||||
|
|
@ -479,12 +482,18 @@ bool LLURLRequest::configure()
|
||||||
case HTTP_HEAD:
|
case HTTP_HEAD:
|
||||||
mDetail->mCurlRequest->setopt(CURLOPT_HEADER, 1);
|
mDetail->mCurlRequest->setopt(CURLOPT_HEADER, 1);
|
||||||
mDetail->mCurlRequest->setopt(CURLOPT_NOBODY, 1);
|
mDetail->mCurlRequest->setopt(CURLOPT_NOBODY, 1);
|
||||||
mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1);
|
if (mFollowRedirects)
|
||||||
|
{
|
||||||
|
mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1);
|
||||||
|
}
|
||||||
rv = true;
|
rv = true;
|
||||||
break;
|
break;
|
||||||
case HTTP_GET:
|
case HTTP_GET:
|
||||||
mDetail->mCurlRequest->setopt(CURLOPT_HTTPGET, 1);
|
mDetail->mCurlRequest->setopt(CURLOPT_HTTPGET, 1);
|
||||||
mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1);
|
if (mFollowRedirects)
|
||||||
|
{
|
||||||
|
mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1);
|
||||||
|
}
|
||||||
|
|
||||||
// Set Accept-Encoding to allow response compression
|
// Set Accept-Encoding to allow response compression
|
||||||
mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, "");
|
mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, "");
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ public:
|
||||||
*
|
*
|
||||||
* @param action One of the ERequestAction enumerations.
|
* @param action One of the ERequestAction enumerations.
|
||||||
*/
|
*/
|
||||||
LLURLRequest(ERequestAction action);
|
LLURLRequest(ERequestAction action, bool follow_redirects = true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Constructor.
|
* @brief Constructor.
|
||||||
|
|
@ -103,7 +103,7 @@ public:
|
||||||
* @param action One of the ERequestAction enumerations.
|
* @param action One of the ERequestAction enumerations.
|
||||||
* @param url The url of the request. It should already be encoded.
|
* @param url The url of the request. It should already be encoded.
|
||||||
*/
|
*/
|
||||||
LLURLRequest(ERequestAction action, const std::string& url);
|
LLURLRequest(ERequestAction action, const std::string& url, bool follow_redirects = true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Destructor.
|
* @brief Destructor.
|
||||||
|
|
@ -219,10 +219,11 @@ protected:
|
||||||
};
|
};
|
||||||
EState mState;
|
EState mState;
|
||||||
ERequestAction mAction;
|
ERequestAction mAction;
|
||||||
|
bool mFollowRedirects;
|
||||||
LLURLRequestDetail* mDetail;
|
LLURLRequestDetail* mDetail;
|
||||||
LLIOPipe::ptr_t mCompletionCallback;
|
LLIOPipe::ptr_t mCompletionCallback;
|
||||||
S32 mRequestTransferedBytes;
|
S32 mRequestTransferedBytes;
|
||||||
S32 mResponseTransferedBytes;
|
S32 mResponseTransferedBytes;
|
||||||
|
|
||||||
static CURLcode _sslCtxCallback(CURL * curl, void *sslctx, void *param);
|
static CURLcode _sslCtxCallback(CURL * curl, void *sslctx, void *param);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,16 @@ std::string LLPluginCookieStore::Cookie::getKey() const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string LLPluginCookieStore::Cookie::getDomain() const
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
if(mDomainEnd > mDomainStart)
|
||||||
|
{
|
||||||
|
result += mCookie.substr(mDomainStart, mDomainEnd - mDomainStart);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool LLPluginCookieStore::Cookie::parse(const std::string &host)
|
bool LLPluginCookieStore::Cookie::parse(const std::string &host)
|
||||||
{
|
{
|
||||||
bool first_field = true;
|
bool first_field = true;
|
||||||
|
|
@ -662,3 +672,21 @@ void LLPluginCookieStore::removeCookie(const std::string &key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LLPluginCookieStore::removeCookiesByDomain(const std::string &domain)
|
||||||
|
{
|
||||||
|
cookie_map_t::iterator iter = mCookies.begin();
|
||||||
|
while(iter != mCookies.end())
|
||||||
|
{
|
||||||
|
if(iter->second->getDomain() == domain)
|
||||||
|
{
|
||||||
|
cookie_map_t::iterator doErase = iter;
|
||||||
|
iter++;
|
||||||
|
delete doErase->second;
|
||||||
|
mCookies.erase(doErase);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,8 @@ public:
|
||||||
// quote or unquote a string as per the definition of 'quoted-string' in rfc2616
|
// quote or unquote a string as per the definition of 'quoted-string' in rfc2616
|
||||||
static std::string quoteString(const std::string &s);
|
static std::string quoteString(const std::string &s);
|
||||||
static std::string unquoteString(const std::string &s);
|
static std::string unquoteString(const std::string &s);
|
||||||
|
|
||||||
|
void removeCookiesByDomain(const std::string &domain);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
@ -79,6 +81,7 @@ private:
|
||||||
|
|
||||||
// Construct a string from the cookie that uniquely represents it, to be used as a key in a std::map.
|
// Construct a string from the cookie that uniquely represents it, to be used as a key in a std::map.
|
||||||
std::string getKey() const;
|
std::string getKey() const;
|
||||||
|
std::string getDomain() const;
|
||||||
|
|
||||||
const std::string &getCookie() const { return mCookie; };
|
const std::string &getCookie() const { return mCookie; };
|
||||||
bool isSessionCookie() const { return mDate.isNull(); };
|
bool isSessionCookie() const { return mDate.isNull(); };
|
||||||
|
|
|
||||||
|
|
@ -364,35 +364,55 @@ void LLRenderTarget::release()
|
||||||
|
|
||||||
sBytesAllocated -= mResX*mResY*4;
|
sBytesAllocated -= mResX*mResY*4;
|
||||||
}
|
}
|
||||||
else if (mUseDepth && mFBO)
|
else if (mFBO)
|
||||||
{ //detach shared depth buffer
|
{
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
|
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
|
||||||
if (mStencil)
|
|
||||||
{ //attached as a renderbuffer
|
if (mUseDepth)
|
||||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
|
{ //detach shared depth buffer
|
||||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
|
if (mStencil)
|
||||||
mStencil = false;
|
{ //attached as a renderbuffer
|
||||||
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
|
||||||
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
|
||||||
|
mStencil = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ //attached as a texture
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0);
|
||||||
|
}
|
||||||
|
mUseDepth = false;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{ //attached as a texture
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0);
|
// Detach any extra color buffers (e.g. SRGB spec buffers)
|
||||||
|
//
|
||||||
|
if (mFBO && (mTex.size() > 1))
|
||||||
|
{
|
||||||
|
S32 z;
|
||||||
|
for (z = mTex.size() - 1; z >= 1; z--)
|
||||||
|
{
|
||||||
|
sBytesAllocated -= mResX*mResY*4;
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+z, LLTexUnit::getInternalType(mUsage), 0, 0);
|
||||||
|
stop_glerror();
|
||||||
|
LLImageGL::deleteTextures(1, &mTex[z]);
|
||||||
}
|
}
|
||||||
mUseDepth = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mFBO)
|
if (mFBO)
|
||||||
{
|
{
|
||||||
glDeleteFramebuffers(1, (GLuint *) &mFBO);
|
glDeleteFramebuffers(1, (GLuint *) &mFBO);
|
||||||
|
stop_glerror();
|
||||||
mFBO = 0;
|
mFBO = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mTex.size() > 0)
|
if (mTex.size() > 0)
|
||||||
{
|
{
|
||||||
sBytesAllocated -= mResX*mResY*4*mTex.size();
|
sBytesAllocated -= mResX*mResY*4;
|
||||||
LLImageGL::deleteTextures(mTex.size(), &mTex[0]);
|
LLImageGL::deleteTextures(1, &mTex[0]);
|
||||||
|
}
|
||||||
|
|
||||||
mTex.clear();
|
mTex.clear();
|
||||||
mInternalFormat.clear();
|
mInternalFormat.clear();
|
||||||
}
|
|
||||||
|
|
||||||
mResX = mResY = 0;
|
mResX = mResY = 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ set(llui_SOURCE_FILES
|
||||||
llmultislider.cpp
|
llmultislider.cpp
|
||||||
llmultisliderctrl.cpp
|
llmultisliderctrl.cpp
|
||||||
llnotifications.cpp
|
llnotifications.cpp
|
||||||
|
llnotificationslistener.cpp
|
||||||
llnotificationsutil.cpp
|
llnotificationsutil.cpp
|
||||||
llpanel.cpp
|
llpanel.cpp
|
||||||
llprogressbar.cpp
|
llprogressbar.cpp
|
||||||
|
|
@ -128,6 +129,7 @@ set(llui_SOURCE_FILES
|
||||||
llviewmodel.cpp
|
llviewmodel.cpp
|
||||||
llview.cpp
|
llview.cpp
|
||||||
llviewquery.cpp
|
llviewquery.cpp
|
||||||
|
llviewereventrecorder.cpp
|
||||||
llwindowshade.cpp
|
llwindowshade.cpp
|
||||||
llxuiparser.cpp
|
llxuiparser.cpp
|
||||||
)
|
)
|
||||||
|
|
@ -183,6 +185,7 @@ set(llui_HEADER_FILES
|
||||||
llmultislider.h
|
llmultislider.h
|
||||||
llnotificationptr.h
|
llnotificationptr.h
|
||||||
llnotifications.h
|
llnotifications.h
|
||||||
|
llnotificationslistener.h
|
||||||
llnotificationsutil.h
|
llnotificationsutil.h
|
||||||
llnotificationtemplate.h
|
llnotificationtemplate.h
|
||||||
llnotificationvisibilityrule.h
|
llnotificationvisibilityrule.h
|
||||||
|
|
@ -240,6 +243,7 @@ set(llui_HEADER_FILES
|
||||||
llviewinject.h
|
llviewinject.h
|
||||||
llviewmodel.h
|
llviewmodel.h
|
||||||
llview.h
|
llview.h
|
||||||
|
llviewereventrecorder.h
|
||||||
llviewquery.h
|
llviewquery.h
|
||||||
llwindowshade.h
|
llwindowshade.h
|
||||||
llxuiparser.h
|
llxuiparser.h
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@
|
||||||
#include "lluictrlfactory.h"
|
#include "lluictrlfactory.h"
|
||||||
#include "llhelp.h"
|
#include "llhelp.h"
|
||||||
#include "lldockablefloater.h"
|
#include "lldockablefloater.h"
|
||||||
|
#include "llviewereventrecorder.h"
|
||||||
|
|
||||||
static LLDefaultChildRegistry::Register<LLButton> r("button");
|
static LLDefaultChildRegistry::Register<LLButton> r("button");
|
||||||
|
|
||||||
|
|
@ -443,6 +444,8 @@ BOOL LLButton::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||||
*/
|
*/
|
||||||
LLUICtrl::handleMouseDown(x, y, mask);
|
LLUICtrl::handleMouseDown(x, y, mask);
|
||||||
|
|
||||||
|
LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname());
|
||||||
|
|
||||||
if(mMouseDownSignal) (*mMouseDownSignal)(this, LLSD());
|
if(mMouseDownSignal) (*mMouseDownSignal)(this, LLSD());
|
||||||
|
|
||||||
mMouseDownTimer.start();
|
mMouseDownTimer.start();
|
||||||
|
|
@ -473,6 +476,7 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
|
||||||
* by calling LLUICtrl::mMouseUpSignal(x, y, mask);
|
* by calling LLUICtrl::mMouseUpSignal(x, y, mask);
|
||||||
*/
|
*/
|
||||||
LLUICtrl::handleMouseUp(x, y, mask);
|
LLUICtrl::handleMouseUp(x, y, mask);
|
||||||
|
LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname());
|
||||||
|
|
||||||
// Regardless of where mouseup occurs, handle callback
|
// Regardless of where mouseup occurs, handle callback
|
||||||
if(mMouseUpSignal) (*mMouseUpSignal)(this, LLSD());
|
if(mMouseUpSignal) (*mMouseUpSignal)(this, LLSD());
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,8 @@ public:
|
||||||
|
|
||||||
virtual void draw();
|
virtual void draw();
|
||||||
virtual void onCommit();
|
virtual void onCommit();
|
||||||
/*virtual*/ void onFocusReceived();
|
/*virtual*/ void onFocusReceived();
|
||||||
/*virtual*/ void onFocusLost();
|
/*virtual*/ void onFocusLost();
|
||||||
|
|
||||||
void enableSingleLineMode(bool single_line_mode);
|
void enableSingleLineMode(bool single_line_mode);
|
||||||
boost::signals2::connection setTextExpandedCallback(const commit_signal_t::slot_type& cb);
|
boost::signals2::connection setTextExpandedCallback(const commit_signal_t::slot_type& cb);
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
// mini-map floater, etc.
|
// mini-map floater, etc.
|
||||||
|
|
||||||
#include "linden_common.h"
|
#include "linden_common.h"
|
||||||
|
#include "llviewereventrecorder.h"
|
||||||
#include "llfloater.h"
|
#include "llfloater.h"
|
||||||
|
|
||||||
#include "llfocusmgr.h"
|
#include "llfocusmgr.h"
|
||||||
|
|
@ -509,8 +509,8 @@ LLFloater::~LLFloater()
|
||||||
|
|
||||||
if( gFocusMgr.childHasKeyboardFocus(this))
|
if( gFocusMgr.childHasKeyboardFocus(this))
|
||||||
{
|
{
|
||||||
// Just in case we might still have focus here, release it.
|
// Just in case we might still have focus here, release it.
|
||||||
releaseFocus();
|
releaseFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is important so that floaters with persistent rects (i.e., those
|
// This is important so that floaters with persistent rects (i.e., those
|
||||||
|
|
@ -642,7 +642,10 @@ void LLFloater::handleVisibilityChange ( BOOL new_visibility )
|
||||||
|
|
||||||
void LLFloater::openFloater(const LLSD& key)
|
void LLFloater::openFloater(const LLSD& key)
|
||||||
{
|
{
|
||||||
llinfos << "Opening floater " << getName() << llendl;
|
llinfos << "Opening floater " << getName() << " full path: " << getPathname() << llendl;
|
||||||
|
|
||||||
|
LLViewerEventRecorder::instance().logVisibilityChange( getPathname(), getName(), true,"floater"); // Last param is event subtype or empty string
|
||||||
|
|
||||||
mKey = key; // in case we need to open ourselves again
|
mKey = key; // in case we need to open ourselves again
|
||||||
|
|
||||||
if (getSoundFlags() != SILENT
|
if (getSoundFlags() != SILENT
|
||||||
|
|
@ -696,6 +699,7 @@ void LLFloater::openFloater(const LLSD& key)
|
||||||
void LLFloater::closeFloater(bool app_quitting)
|
void LLFloater::closeFloater(bool app_quitting)
|
||||||
{
|
{
|
||||||
llinfos << "Closing floater " << getName() << llendl;
|
llinfos << "Closing floater " << getName() << llendl;
|
||||||
|
LLViewerEventRecorder::instance().logVisibilityChange( getPathname(), getName(), false,"floater"); // Last param is event subtype or empty string
|
||||||
if (app_quitting)
|
if (app_quitting)
|
||||||
{
|
{
|
||||||
LLFloater::sQuitting = true;
|
LLFloater::sQuitting = true;
|
||||||
|
|
@ -1335,7 +1339,7 @@ void LLFloater::setFocus( BOOL b )
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LLUICtrl* last_focus = gFocusMgr.getLastFocusForGroup(this);
|
LLView* last_focus = gFocusMgr.getLastFocusForGroup(this);
|
||||||
// a descendent already has focus
|
// a descendent already has focus
|
||||||
BOOL child_had_focus = hasFocus();
|
BOOL child_had_focus = hasFocus();
|
||||||
|
|
||||||
|
|
@ -1542,6 +1546,17 @@ BOOL LLFloater::handleScrollWheel(S32 x, S32 y, S32 clicks)
|
||||||
return TRUE;//always
|
return TRUE;//always
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// virtual
|
||||||
|
BOOL LLFloater::handleMouseUp(S32 x, S32 y, MASK mask)
|
||||||
|
{
|
||||||
|
lldebugs << "LLFloater::handleMouseUp calling LLPanel (really LLView)'s handleMouseUp (first initialized xui to: " << getPathname() << " )" << llendl;
|
||||||
|
BOOL handled = LLPanel::handleMouseUp(x,y,mask); // Not implemented in LLPanel so this actually calls LLView
|
||||||
|
if (handled) {
|
||||||
|
LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname());
|
||||||
|
}
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
BOOL LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)
|
BOOL LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||||
{
|
{
|
||||||
|
|
@ -1562,7 +1577,11 @@ BOOL LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bringToFront( x, y );
|
bringToFront( x, y );
|
||||||
return LLPanel::handleMouseDown( x, y, mask );
|
BOOL handled = LLPanel::handleMouseDown( x, y, mask );
|
||||||
|
if (handled) {
|
||||||
|
LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname());
|
||||||
|
}
|
||||||
|
return handled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -289,6 +289,7 @@ public:
|
||||||
S32 getHeaderHeight() const { return mHeaderHeight; }
|
S32 getHeaderHeight() const { return mHeaderHeight; }
|
||||||
|
|
||||||
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
|
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
|
||||||
|
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
|
||||||
virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
|
virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
|
||||||
virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
|
virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
|
||||||
virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask);
|
virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask);
|
||||||
|
|
|
||||||
|
|
@ -469,7 +469,7 @@ void LLFocusMgr::setAppHasFocus(BOOL focus)
|
||||||
mAppHasFocus = focus;
|
mAppHasFocus = focus;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLUICtrl* LLFocusMgr::getLastFocusForGroup(LLView* subtree_root) const
|
LLView* LLFocusMgr::getLastFocusForGroup(LLView* subtree_root) const
|
||||||
{
|
{
|
||||||
if (subtree_root)
|
if (subtree_root)
|
||||||
{
|
{
|
||||||
|
|
@ -477,7 +477,7 @@ LLUICtrl* LLFocusMgr::getLastFocusForGroup(LLView* subtree_root) const
|
||||||
if (found_it != mImpl->mFocusHistory.end())
|
if (found_it != mImpl->mFocusHistory.end())
|
||||||
{
|
{
|
||||||
// found last focus for this subtree
|
// found last focus for this subtree
|
||||||
return static_cast<LLUICtrl*>(found_it->second.get());
|
return found_it->second.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ public:
|
||||||
void triggerFocusFlash();
|
void triggerFocusFlash();
|
||||||
BOOL getAppHasFocus() const { return mAppHasFocus; }
|
BOOL getAppHasFocus() const { return mAppHasFocus; }
|
||||||
void setAppHasFocus(BOOL focus);
|
void setAppHasFocus(BOOL focus);
|
||||||
LLUICtrl* getLastFocusForGroup(LLView* subtree_root) const;
|
LLView* getLastFocusForGroup(LLView* subtree_root) const;
|
||||||
void clearLastFocusForGroup(LLView* subtree_root);
|
void clearLastFocusForGroup(LLView* subtree_root);
|
||||||
|
|
||||||
// If setKeyboardFocus(NULL) is called, and there is a non-NULL default
|
// If setKeyboardFocus(NULL) is called, and there is a non-NULL default
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ LLFolderView::LLFolderView(const Params& p)
|
||||||
mAutoOpenCandidate = NULL;
|
mAutoOpenCandidate = NULL;
|
||||||
mAutoOpenTimer.stop();
|
mAutoOpenTimer.stop();
|
||||||
mKeyboardSelection = FALSE;
|
mKeyboardSelection = FALSE;
|
||||||
mIndentation = p.folder_indentation;
|
mIndentation = getParentFolder() ? getParentFolder()->getIndentation() + mLocalIndentation : 0;
|
||||||
|
|
||||||
//clear label
|
//clear label
|
||||||
// go ahead and render root folder as usual
|
// go ahead and render root folder as usual
|
||||||
|
|
@ -1621,7 +1621,7 @@ void LLFolderView::update()
|
||||||
{
|
{
|
||||||
getFolderViewModel()->getFilter().clearModified();
|
getFolderViewModel()->getFilter().clearModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
// automatically show matching items, and select first one if we had a selection
|
// automatically show matching items, and select first one if we had a selection
|
||||||
if (mNeedsAutoSelect)
|
if (mNeedsAutoSelect)
|
||||||
{
|
{
|
||||||
|
|
@ -1661,13 +1661,13 @@ void LLFolderView::update()
|
||||||
|
|
||||||
BOOL is_visible = isInVisibleChain();
|
BOOL is_visible = isInVisibleChain();
|
||||||
|
|
||||||
// Puts folders/items in proper positions
|
//Puts folders/items in proper positions
|
||||||
// arrange() takes the model filter flag into account and call sort() if necessary (CHUI-849)
|
// arrange() takes the model filter flag into account and call sort() if necessary (CHUI-849)
|
||||||
// It also handles the open/close folder animation
|
// It also handles the open/close folder animation
|
||||||
if (is_visible)
|
if ( is_visible )
|
||||||
{
|
{
|
||||||
sanitizeSelection();
|
sanitizeSelection();
|
||||||
if (needsArrange())
|
if( needsArrange() )
|
||||||
{
|
{
|
||||||
S32 height = 0;
|
S32 height = 0;
|
||||||
S32 width = 0;
|
S32 width = 0;
|
||||||
|
|
|
||||||
|
|
@ -307,7 +307,12 @@ std::set<LLFolderViewItem*> LLFolderViewItem::getSelectionList() const
|
||||||
// addToFolder() returns TRUE if it succeeds. FALSE otherwise
|
// addToFolder() returns TRUE if it succeeds. FALSE otherwise
|
||||||
void LLFolderViewItem::addToFolder(LLFolderViewFolder* folder)
|
void LLFolderViewItem::addToFolder(LLFolderViewFolder* folder)
|
||||||
{
|
{
|
||||||
folder->addItem(this);
|
folder->addItem(this);
|
||||||
|
|
||||||
|
// Compute indentation since parent folder changed
|
||||||
|
mIndentation = (getParentFolder())
|
||||||
|
? getParentFolder()->getIndentation() + mLocalIndentation
|
||||||
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -940,6 +945,11 @@ LLFolderViewFolder::~LLFolderViewFolder( void )
|
||||||
void LLFolderViewFolder::addToFolder(LLFolderViewFolder* folder)
|
void LLFolderViewFolder::addToFolder(LLFolderViewFolder* folder)
|
||||||
{
|
{
|
||||||
folder->addFolder(this);
|
folder->addFolder(this);
|
||||||
|
|
||||||
|
// Compute indentation since parent folder changed
|
||||||
|
mIndentation = (getParentFolder())
|
||||||
|
? getParentFolder()->getIndentation() + mLocalIndentation
|
||||||
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static LLFastTimer::DeclareTimer FTM_ARRANGE("Arrange");
|
static LLFastTimer::DeclareTimer FTM_ARRANGE("Arrange");
|
||||||
|
|
@ -1109,7 +1119,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height )
|
||||||
|
|
||||||
BOOL LLFolderViewFolder::needsArrange()
|
BOOL LLFolderViewFolder::needsArrange()
|
||||||
{
|
{
|
||||||
return mLastArrangeGeneration < getRoot()->getArrangeGeneration();
|
return mLastArrangeGeneration < getRoot()->getArrangeGeneration();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Passes selection information on to children and record selection
|
// Passes selection information on to children and record selection
|
||||||
|
|
|
||||||
|
|
@ -1206,6 +1206,7 @@ LLNotifications::LLNotifications()
|
||||||
: LLNotificationChannelBase(LLNotificationFilters::includeEverything),
|
: LLNotificationChannelBase(LLNotificationFilters::includeEverything),
|
||||||
mIgnoreAllNotifications(false)
|
mIgnoreAllNotifications(false)
|
||||||
{
|
{
|
||||||
|
mListener.reset(new LLNotificationsListener(*this));
|
||||||
LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2));
|
LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,8 @@
|
||||||
#include "llrefcount.h"
|
#include "llrefcount.h"
|
||||||
#include "llsdparam.h"
|
#include "llsdparam.h"
|
||||||
|
|
||||||
|
#include "llnotificationslistener.h"
|
||||||
|
|
||||||
class LLAvatarName;
|
class LLAvatarName;
|
||||||
typedef enum e_notification_priority
|
typedef enum e_notification_priority
|
||||||
{
|
{
|
||||||
|
|
@ -978,6 +980,8 @@ private:
|
||||||
|
|
||||||
bool mIgnoreAllNotifications;
|
bool mIgnoreAllNotifications;
|
||||||
|
|
||||||
|
boost::scoped_ptr<LLNotificationsListener> mListener;
|
||||||
|
|
||||||
std::vector<LLNotificationChannelPtr> mDefaultChannels;
|
std::vector<LLNotificationChannelPtr> mDefaultChannels;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,359 @@
|
||||||
|
/**
|
||||||
|
* @file llnotificationslistener.cpp
|
||||||
|
* @author Brad Kittenbrink
|
||||||
|
* @date 2009-07-08
|
||||||
|
* @brief Implementation for llnotificationslistener.
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
|
||||||
|
* Second Life Viewer Source Code
|
||||||
|
* Copyright (C) 2010, Linden Research, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation;
|
||||||
|
* version 2.1 of the License only.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
|
* $/LicenseInfo$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "linden_common.h"
|
||||||
|
#include "llnotificationslistener.h"
|
||||||
|
#include "llnotifications.h"
|
||||||
|
#include "llnotificationtemplate.h"
|
||||||
|
#include "llsd.h"
|
||||||
|
#include "llui.h"
|
||||||
|
|
||||||
|
LLNotificationsListener::LLNotificationsListener(LLNotifications & notifications) :
|
||||||
|
LLEventAPI("LLNotifications",
|
||||||
|
"LLNotifications listener to (e.g.) pop up a notification"),
|
||||||
|
mNotifications(notifications)
|
||||||
|
{
|
||||||
|
add("requestAdd",
|
||||||
|
"Add a notification with specified [\"name\"], [\"substitutions\"] and [\"payload\"].\n"
|
||||||
|
"If optional [\"reply\"] specified, arrange to send user response on that LLEventPump.",
|
||||||
|
&LLNotificationsListener::requestAdd);
|
||||||
|
/* add("listChannels",
|
||||||
|
"Post to [\"reply\"] a map of info on existing channels",
|
||||||
|
&LLNotificationsListener::listChannels,
|
||||||
|
LLSD().with("reply", LLSD()));
|
||||||
|
*/
|
||||||
|
add("listChannelNotifications",
|
||||||
|
"Post to [\"reply\"] an array of info on notifications in channel [\"channel\"]",
|
||||||
|
&LLNotificationsListener::listChannelNotifications,
|
||||||
|
LLSD().with("reply", LLSD()).with("channel", LLSD()));
|
||||||
|
add("respond",
|
||||||
|
"Respond to notification [\"uuid\"] with data in [\"response\"]",
|
||||||
|
&LLNotificationsListener::respond,
|
||||||
|
LLSD().with("uuid", LLSD()));
|
||||||
|
add("cancel",
|
||||||
|
"Cancel notification [\"uuid\"]",
|
||||||
|
&LLNotificationsListener::cancel,
|
||||||
|
LLSD().with("uuid", LLSD()));
|
||||||
|
add("ignore",
|
||||||
|
"Ignore future notification [\"name\"]\n"
|
||||||
|
"(from <notification name= > in notifications.xml)\n"
|
||||||
|
"according to boolean [\"ignore\"].\n"
|
||||||
|
"If [\"name\"] is omitted or undefined, [un]ignore all future notifications.\n"
|
||||||
|
"Note that ignored notifications are not forwarded unless intercepted before\n"
|
||||||
|
"the \"Ignore\" channel.",
|
||||||
|
&LLNotificationsListener::ignore);
|
||||||
|
add("forward",
|
||||||
|
"Forward to [\"pump\"] future notifications on channel [\"channel\"]\n"
|
||||||
|
"according to boolean [\"forward\"]. When enabled, only types matching\n"
|
||||||
|
"[\"types\"] are forwarded, as follows:\n"
|
||||||
|
"omitted or undefined: forward all notifications\n"
|
||||||
|
"string: forward only the specific named [sig]type\n"
|
||||||
|
"array of string: forward any notification matching any named [sig]type.\n"
|
||||||
|
"When boolean [\"respond\"] is true, we auto-respond to each forwarded\n"
|
||||||
|
"notification.",
|
||||||
|
&LLNotificationsListener::forward,
|
||||||
|
LLSD().with("channel", LLSD()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is here in the .cpp file so we don't need the definition of class
|
||||||
|
// Forwarder in the header file.
|
||||||
|
LLNotificationsListener::~LLNotificationsListener()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLNotificationsListener::requestAdd(const LLSD& event_data) const
|
||||||
|
{
|
||||||
|
if(event_data.has("reply"))
|
||||||
|
{
|
||||||
|
mNotifications.add(event_data["name"],
|
||||||
|
event_data["substitutions"],
|
||||||
|
event_data["payload"],
|
||||||
|
boost::bind(&LLNotificationsListener::NotificationResponder,
|
||||||
|
this,
|
||||||
|
event_data["reply"].asString(),
|
||||||
|
_1, _2
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mNotifications.add(event_data["name"],
|
||||||
|
event_data["substitutions"],
|
||||||
|
event_data["payload"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLNotificationsListener::NotificationResponder(const std::string& reply_pump,
|
||||||
|
const LLSD& notification,
|
||||||
|
const LLSD& response) const
|
||||||
|
{
|
||||||
|
LLSD reponse_event;
|
||||||
|
reponse_event["notification"] = notification;
|
||||||
|
reponse_event["response"] = response;
|
||||||
|
LLEventPumps::getInstance()->obtain(reply_pump).post(reponse_event);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
void LLNotificationsListener::listChannels(const LLSD& params) const
|
||||||
|
{
|
||||||
|
LLReqID reqID(params);
|
||||||
|
LLSD response(reqID.makeResponse());
|
||||||
|
for (LLNotifications::
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (LLNotifications::ChannelMap::const_iterator cmi(mNotifications.mChannels.begin()),
|
||||||
|
cmend(mNotifications.mChannels.end());
|
||||||
|
cmi != cmend; ++cmi)
|
||||||
|
{
|
||||||
|
LLSD channelInfo;
|
||||||
|
channelInfo["parent"] = cmi->second->getParentChannelName();
|
||||||
|
response[cmi->first] = channelInfo;
|
||||||
|
}
|
||||||
|
LLEventPumps::instance().obtain(params["reply"]).post(response);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
void LLNotificationsListener::listChannelNotifications(const LLSD& params) const
|
||||||
|
{
|
||||||
|
LLReqID reqID(params);
|
||||||
|
LLSD response(reqID.makeResponse());
|
||||||
|
LLNotificationChannelPtr channel(mNotifications.getChannel(params["channel"]));
|
||||||
|
if (channel)
|
||||||
|
{
|
||||||
|
LLSD notifications(LLSD::emptyArray());
|
||||||
|
for (LLNotificationChannel::Iterator ni(channel->begin()), nend(channel->end());
|
||||||
|
ni != nend; ++ni)
|
||||||
|
{
|
||||||
|
notifications.append(asLLSD(*ni));
|
||||||
|
}
|
||||||
|
response["notifications"] = notifications;
|
||||||
|
}
|
||||||
|
LLEventPumps::instance().obtain(params["reply"]).post(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLNotificationsListener::respond(const LLSD& params) const
|
||||||
|
{
|
||||||
|
LLNotificationPtr notification(mNotifications.find(params["uuid"]));
|
||||||
|
if (notification)
|
||||||
|
{
|
||||||
|
notification->respond(params["response"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLNotificationsListener::cancel(const LLSD& params) const
|
||||||
|
{
|
||||||
|
LLNotificationPtr notification(mNotifications.find(params["uuid"]));
|
||||||
|
if (notification)
|
||||||
|
{
|
||||||
|
mNotifications.cancel(notification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLNotificationsListener::ignore(const LLSD& params) const
|
||||||
|
{
|
||||||
|
// Calling a method named "ignore", but omitting its "ignore" Boolean
|
||||||
|
// argument, should by default cause something to be ignored. Explicitly
|
||||||
|
// pass ["ignore"] = false to cancel ignore.
|
||||||
|
bool ignore = true;
|
||||||
|
if (params.has("ignore"))
|
||||||
|
{
|
||||||
|
ignore = params["ignore"].asBoolean();
|
||||||
|
}
|
||||||
|
// This method can be used to affect either a single notification name or
|
||||||
|
// all future notifications. The two use substantially different mechanisms.
|
||||||
|
if (params["name"].isDefined())
|
||||||
|
{
|
||||||
|
// ["name"] was passed: ignore just that notification
|
||||||
|
LLNotificationTemplatePtr templatep = mNotifications.getTemplate(params["name"]);
|
||||||
|
if (templatep)
|
||||||
|
{
|
||||||
|
templatep->mForm->setIgnored(ignore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// no ["name"]: ignore all future notifications
|
||||||
|
mNotifications.setIgnoreAllNotifications(ignore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LLNotificationsListener::Forwarder: public LLEventTrackable
|
||||||
|
{
|
||||||
|
LOG_CLASS(LLNotificationsListener::Forwarder);
|
||||||
|
public:
|
||||||
|
Forwarder(LLNotifications& llnotifications, const std::string& channel):
|
||||||
|
mNotifications(llnotifications),
|
||||||
|
mRespond(false)
|
||||||
|
{
|
||||||
|
// Connect to the specified channel on construction. Because
|
||||||
|
// LLEventTrackable is a base, we should automatically disconnect when
|
||||||
|
// destroyed.
|
||||||
|
LLNotificationChannelPtr channelptr(llnotifications.getChannel(channel));
|
||||||
|
if (channelptr)
|
||||||
|
{
|
||||||
|
// Insert our processing as a "passed filter" listener. This way
|
||||||
|
// we get to run before all the "changed" listeners, and we get to
|
||||||
|
// swipe it (hide it from the other listeners) if desired.
|
||||||
|
channelptr->connectPassedFilter(boost::bind(&Forwarder::handle, this, _1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPumpName(const std::string& name) { mPumpName = name; }
|
||||||
|
void setTypes(const LLSD& types) { mTypes = types; }
|
||||||
|
void setRespond(bool respond) { mRespond = respond; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool handle(const LLSD& notification) const;
|
||||||
|
bool matchType(const LLSD& filter, const std::string& type) const;
|
||||||
|
|
||||||
|
LLNotifications& mNotifications;
|
||||||
|
std::string mPumpName;
|
||||||
|
LLSD mTypes;
|
||||||
|
bool mRespond;
|
||||||
|
};
|
||||||
|
|
||||||
|
void LLNotificationsListener::forward(const LLSD& params)
|
||||||
|
{
|
||||||
|
std::string channel(params["channel"]);
|
||||||
|
// First decide whether we're supposed to start forwarding or stop it.
|
||||||
|
// Default to true.
|
||||||
|
bool forward = true;
|
||||||
|
if (params.has("forward"))
|
||||||
|
{
|
||||||
|
forward = params["forward"].asBoolean();
|
||||||
|
}
|
||||||
|
if (! forward)
|
||||||
|
{
|
||||||
|
// This is a request to stop forwarding notifications on the specified
|
||||||
|
// channel. The rest of the params don't matter.
|
||||||
|
// Because mForwarders contains scoped_ptrs, erasing the map entry
|
||||||
|
// DOES delete the heap Forwarder object. Because Forwarder derives
|
||||||
|
// from LLEventTrackable, destroying it disconnects it from the
|
||||||
|
// channel.
|
||||||
|
mForwarders.erase(channel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// From here on, we know we're being asked to start (or modify) forwarding
|
||||||
|
// on the specified channel. Find or create an appropriate Forwarder.
|
||||||
|
ForwarderMap::iterator
|
||||||
|
entry(mForwarders.insert(ForwarderMap::value_type(channel, ForwarderMap::mapped_type())).first);
|
||||||
|
if (! entry->second)
|
||||||
|
{
|
||||||
|
entry->second.reset(new Forwarder(mNotifications, channel));
|
||||||
|
}
|
||||||
|
// Now, whether this Forwarder is brand-new or not, update it with the new
|
||||||
|
// request info.
|
||||||
|
Forwarder& fwd(*entry->second);
|
||||||
|
fwd.setPumpName(params["pump"]);
|
||||||
|
fwd.setTypes(params["types"]);
|
||||||
|
fwd.setRespond(params["respond"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LLNotificationsListener::Forwarder::handle(const LLSD& notification) const
|
||||||
|
{
|
||||||
|
LL_INFOS("LLNotificationsListener") << "handle(" << notification << ")" << LL_ENDL;
|
||||||
|
if (notification["sigtype"].asString() == "delete")
|
||||||
|
{
|
||||||
|
LL_INFOS("LLNotificationsListener") << "ignoring delete" << LL_ENDL;
|
||||||
|
// let other listeners see the "delete" operation
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LLNotificationPtr note(mNotifications.find(notification["id"]));
|
||||||
|
if (! note)
|
||||||
|
{
|
||||||
|
LL_INFOS("LLNotificationsListener") << notification["id"] << " not found" << LL_ENDL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (! matchType(mTypes, note->getType()))
|
||||||
|
{
|
||||||
|
LL_INFOS("LLNotificationsListener") << "didn't match types " << mTypes << LL_ENDL;
|
||||||
|
// We're not supposed to intercept this particular notification. Let
|
||||||
|
// other listeners process it.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LL_INFOS("LLNotificationsListener") << "sending via '" << mPumpName << "'" << LL_ENDL;
|
||||||
|
// This is a notification we care about. Forward it through specified
|
||||||
|
// LLEventPump.
|
||||||
|
LLEventPumps::instance().obtain(mPumpName).post(asLLSD(note));
|
||||||
|
// Are we also being asked to auto-respond?
|
||||||
|
if (mRespond)
|
||||||
|
{
|
||||||
|
LL_INFOS("LLNotificationsListener") << "should respond" << LL_ENDL;
|
||||||
|
note->respond(LLSD::emptyMap());
|
||||||
|
// Did that succeed in removing the notification? Only cancel() if
|
||||||
|
// it's still around -- otherwise we get an LL_ERRS crash!
|
||||||
|
note = mNotifications.find(notification["id"]);
|
||||||
|
if (note)
|
||||||
|
{
|
||||||
|
LL_INFOS("LLNotificationsListener") << "respond() didn't clear, canceling" << LL_ENDL;
|
||||||
|
mNotifications.cancel(note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we've auto-responded to this notification, then it's going to be
|
||||||
|
// deleted. Other listeners would get the change operation, try to look it
|
||||||
|
// up and be baffled by lookup failure. So when we auto-respond, suppress
|
||||||
|
// this notification: don't pass it to other listeners.
|
||||||
|
return mRespond;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LLNotificationsListener::Forwarder::matchType(const LLSD& filter, const std::string& type) const
|
||||||
|
{
|
||||||
|
// Decide whether this notification matches filter:
|
||||||
|
// undefined: forward all notifications
|
||||||
|
if (filter.isUndefined())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// array of string: forward any notification matching any named type
|
||||||
|
if (filter.isArray())
|
||||||
|
{
|
||||||
|
for (LLSD::array_const_iterator ti(filter.beginArray()), tend(filter.endArray());
|
||||||
|
ti != tend; ++ti)
|
||||||
|
{
|
||||||
|
if (ti->asString() == type)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Didn't match any entry in the array
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// string: forward only the specific named type
|
||||||
|
return (filter.asString() == type);
|
||||||
|
}
|
||||||
|
|
||||||
|
LLSD LLNotificationsListener::asLLSD(LLNotificationPtr note)
|
||||||
|
{
|
||||||
|
LLSD notificationInfo(note->asLLSD());
|
||||||
|
// For some reason the following aren't included in LLNotification::asLLSD().
|
||||||
|
notificationInfo["summary"] = note->summarize();
|
||||||
|
notificationInfo["id"] = note->id();
|
||||||
|
notificationInfo["type"] = note->getType();
|
||||||
|
notificationInfo["message"] = note->getMessage();
|
||||||
|
notificationInfo["label"] = note->getLabel();
|
||||||
|
return notificationInfo;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
/**
|
||||||
|
* @file llnotificationslistener.h
|
||||||
|
* @author Brad Kittenbrink
|
||||||
|
* @date 2009-07-08
|
||||||
|
* @brief Wrap subset of LLNotifications API in event API for test scripts.
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
|
||||||
|
* Second Life Viewer Source Code
|
||||||
|
* Copyright (C) 2010, Linden Research, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation;
|
||||||
|
* version 2.1 of the License only.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
|
* $/LicenseInfo$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LL_LLNOTIFICATIONSLISTENER_H
|
||||||
|
#define LL_LLNOTIFICATIONSLISTENER_H
|
||||||
|
|
||||||
|
#include "lleventapi.h"
|
||||||
|
#include "llnotificationptr.h"
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class LLNotifications;
|
||||||
|
class LLSD;
|
||||||
|
|
||||||
|
class LLNotificationsListener : public LLEventAPI
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LLNotificationsListener(LLNotifications & notifications);
|
||||||
|
~LLNotificationsListener();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void requestAdd(LLSD const & event_data) const;
|
||||||
|
|
||||||
|
void NotificationResponder(const std::string& replypump,
|
||||||
|
const LLSD& notification,
|
||||||
|
const LLSD& response) const;
|
||||||
|
|
||||||
|
void listChannels(const LLSD& params) const;
|
||||||
|
void listChannelNotifications(const LLSD& params) const;
|
||||||
|
void respond(const LLSD& params) const;
|
||||||
|
void cancel(const LLSD& params) const;
|
||||||
|
void ignore(const LLSD& params) const;
|
||||||
|
void forward(const LLSD& params);
|
||||||
|
|
||||||
|
static LLSD asLLSD(LLNotificationPtr);
|
||||||
|
|
||||||
|
class Forwarder;
|
||||||
|
typedef std::map<std::string, boost::shared_ptr<Forwarder> > ForwarderMap;
|
||||||
|
ForwarderMap mForwarders;
|
||||||
|
LLNotifications & mNotifications;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LL_LLNOTIFICATIONSLISTENER_H
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
#include "linden_common.h"
|
#include "linden_common.h"
|
||||||
|
|
||||||
#include "lltabcontainer.h"
|
#include "lltabcontainer.h"
|
||||||
|
#include "llviewereventrecorder.h"
|
||||||
#include "llfocusmgr.h"
|
#include "llfocusmgr.h"
|
||||||
#include "lllocalcliprect.h"
|
#include "lllocalcliprect.h"
|
||||||
#include "llrect.h"
|
#include "llrect.h"
|
||||||
|
|
@ -583,6 +583,11 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask )
|
||||||
tab_button->setFocus(TRUE);
|
tab_button->setFocus(TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (handled) {
|
||||||
|
// Note: May need to also capture local coords right here ?
|
||||||
|
LLViewerEventRecorder::instance().update_xui(getPathname( ));
|
||||||
|
}
|
||||||
|
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -634,30 +639,33 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask )
|
||||||
BOOL handled = FALSE;
|
BOOL handled = FALSE;
|
||||||
BOOL has_scroll_arrows = (getMaxScrollPos() > 0) && !getTabsHidden();
|
BOOL has_scroll_arrows = (getMaxScrollPos() > 0) && !getTabsHidden();
|
||||||
|
|
||||||
|
S32 local_x = x - getRect().mLeft;
|
||||||
|
S32 local_y = y - getRect().mBottom;
|
||||||
|
|
||||||
if (has_scroll_arrows)
|
if (has_scroll_arrows)
|
||||||
{
|
{
|
||||||
if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y))
|
if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y))
|
||||||
{
|
{
|
||||||
S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
|
local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
|
||||||
S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
|
local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
|
||||||
handled = mJumpPrevArrowBtn->handleMouseUp(local_x, local_y, mask);
|
handled = mJumpPrevArrowBtn->handleMouseUp(local_x, local_y, mask);
|
||||||
}
|
}
|
||||||
else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y))
|
else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y))
|
||||||
{
|
{
|
||||||
S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft;
|
local_x = x - mJumpNextArrowBtn->getRect().mLeft;
|
||||||
S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom;
|
local_y = y - mJumpNextArrowBtn->getRect().mBottom;
|
||||||
handled = mJumpNextArrowBtn->handleMouseUp(local_x, local_y, mask);
|
handled = mJumpNextArrowBtn->handleMouseUp(local_x, local_y, mask);
|
||||||
}
|
}
|
||||||
else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y))
|
else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y))
|
||||||
{
|
{
|
||||||
S32 local_x = x - mPrevArrowBtn->getRect().mLeft;
|
local_x = x - mPrevArrowBtn->getRect().mLeft;
|
||||||
S32 local_y = y - mPrevArrowBtn->getRect().mBottom;
|
local_y = y - mPrevArrowBtn->getRect().mBottom;
|
||||||
handled = mPrevArrowBtn->handleMouseUp(local_x, local_y, mask);
|
handled = mPrevArrowBtn->handleMouseUp(local_x, local_y, mask);
|
||||||
}
|
}
|
||||||
else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y))
|
else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y))
|
||||||
{
|
{
|
||||||
S32 local_x = x - mNextArrowBtn->getRect().mLeft;
|
local_x = x - mNextArrowBtn->getRect().mLeft;
|
||||||
S32 local_y = y - mNextArrowBtn->getRect().mBottom;
|
local_y = y - mNextArrowBtn->getRect().mBottom;
|
||||||
handled = mNextArrowBtn->handleMouseUp(local_x, local_y, mask);
|
handled = mNextArrowBtn->handleMouseUp(local_x, local_y, mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -681,6 +689,10 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask )
|
||||||
}
|
}
|
||||||
gFocusMgr.setMouseCapture(NULL);
|
gFocusMgr.setMouseCapture(NULL);
|
||||||
}
|
}
|
||||||
|
if (handled) {
|
||||||
|
// Note: may need to capture local coords here
|
||||||
|
LLViewerEventRecorder::instance().update_xui(getPathname( ));
|
||||||
|
}
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1076,21 +1088,21 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
|
||||||
|
|
||||||
if (mIsVertical)
|
if (mIsVertical)
|
||||||
{
|
{
|
||||||
p.name(std::string("vert tab button"));
|
p.name("vtab_"+std::string(child->getName()));
|
||||||
p.image_unselected(mMiddleTabParams.tab_left_image_unselected);
|
p.image_unselected(mMiddleTabParams.tab_left_image_unselected);
|
||||||
p.image_selected(mMiddleTabParams.tab_left_image_selected);
|
p.image_selected(mMiddleTabParams.tab_left_image_selected);
|
||||||
p.follows.flags = p.follows.flags() | FOLLOWS_TOP;
|
p.follows.flags = p.follows.flags() | FOLLOWS_TOP;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p.name(std::string(child->getName()) + " tab");
|
p.name("htab_"+std::string(child->getName()));
|
||||||
p.visible(false);
|
p.visible(false);
|
||||||
p.image_unselected(tab_img);
|
p.image_unselected(tab_img);
|
||||||
p.image_selected(tab_selected_img);
|
p.image_selected(tab_selected_img);
|
||||||
p.follows.flags = p.follows.flags() | (getTabPosition() == TOP ? FOLLOWS_TOP : FOLLOWS_BOTTOM);
|
p.follows.flags = p.follows.flags() | (getTabPosition() == TOP ? FOLLOWS_TOP : FOLLOWS_BOTTOM);
|
||||||
// Try to squeeze in a bit more text
|
// Try to squeeze in a bit more text
|
||||||
p.pad_left( mLabelPadLeft );
|
p.pad_left( mLabelPadLeft );
|
||||||
p.pad_right(2);
|
p.pad_right(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// *TODO : It seems wrong not to use p in both cases considering the way p is initialized
|
// *TODO : It seems wrong not to use p in both cases considering the way p is initialized
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
#define LLUICTRL_CPP
|
#define LLUICTRL_CPP
|
||||||
#include "lluictrl.h"
|
#include "lluictrl.h"
|
||||||
|
#include "llviewereventrecorder.h"
|
||||||
#include "llfocusmgr.h"
|
#include "llfocusmgr.h"
|
||||||
#include "llpanel.h"
|
#include "llpanel.h"
|
||||||
#include "lluictrlfactory.h"
|
#include "lluictrlfactory.h"
|
||||||
|
|
@ -308,22 +308,40 @@ void LLUICtrl::onMouseLeave(S32 x, S32 y, MASK mask)
|
||||||
//virtual
|
//virtual
|
||||||
BOOL LLUICtrl::handleMouseDown(S32 x, S32 y, MASK mask)
|
BOOL LLUICtrl::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
lldebugs << "LLUICtrl::handleMouseDown calling LLView)'s handleMouseUp (first initialized xui to: " << getPathname() << " )" << llendl;
|
||||||
|
|
||||||
BOOL handled = LLView::handleMouseDown(x,y,mask);
|
BOOL handled = LLView::handleMouseDown(x,y,mask);
|
||||||
|
|
||||||
if (mMouseDownSignal)
|
if (mMouseDownSignal)
|
||||||
{
|
{
|
||||||
(*mMouseDownSignal)(this,x,y,mask);
|
(*mMouseDownSignal)(this,x,y,mask);
|
||||||
}
|
}
|
||||||
|
lldebugs << "LLUICtrl::handleMousedown - handled is returning as: " << handled << " " << llendl;
|
||||||
|
|
||||||
|
if (handled) {
|
||||||
|
LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-56,-56,getPathname());
|
||||||
|
}
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
//virtual
|
//virtual
|
||||||
BOOL LLUICtrl::handleMouseUp(S32 x, S32 y, MASK mask)
|
BOOL LLUICtrl::handleMouseUp(S32 x, S32 y, MASK mask)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
lldebugs << "LLUICtrl::handleMouseUp calling LLView)'s handleMouseUp (first initialized xui to: " << getPathname() << " )" << llendl;
|
||||||
|
|
||||||
BOOL handled = LLView::handleMouseUp(x,y,mask);
|
BOOL handled = LLView::handleMouseUp(x,y,mask);
|
||||||
|
if (handled) {
|
||||||
|
LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-56,-56,getPathname());
|
||||||
|
}
|
||||||
if (mMouseUpSignal)
|
if (mMouseUpSignal)
|
||||||
{
|
{
|
||||||
(*mMouseUpSignal)(this,x,y,mask);
|
(*mMouseUpSignal)(this,x,y,mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lldebugs << "LLUICtrl::handleMouseUp - handled for xui " << getPathname() << " - is returning as: " << handled << " " << llendl;
|
||||||
|
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,9 @@
|
||||||
#include "lluictrlfactory.h"
|
#include "lluictrlfactory.h"
|
||||||
#include "lltooltip.h"
|
#include "lltooltip.h"
|
||||||
#include "llsdutil.h"
|
#include "llsdutil.h"
|
||||||
|
#include "llsdserialize.h"
|
||||||
|
#include "llviewereventrecorder.h"
|
||||||
|
#include "llkeyboard.h"
|
||||||
// for ui edit hack
|
// for ui edit hack
|
||||||
#include "llbutton.h"
|
#include "llbutton.h"
|
||||||
#include "lllineeditor.h"
|
#include "lllineeditor.h"
|
||||||
|
|
@ -642,13 +644,27 @@ void LLView::setVisible(BOOL visible)
|
||||||
// virtual
|
// virtual
|
||||||
void LLView::handleVisibilityChange ( BOOL new_visibility )
|
void LLView::handleVisibilityChange ( BOOL new_visibility )
|
||||||
{
|
{
|
||||||
|
BOOL old_visibility;
|
||||||
BOOST_FOREACH(LLView* viewp, mChildList)
|
BOOST_FOREACH(LLView* viewp, mChildList)
|
||||||
{
|
{
|
||||||
// only views that are themselves visible will have their overall visibility affected by their ancestors
|
// only views that are themselves visible will have their overall visibility affected by their ancestors
|
||||||
if (viewp->getVisible())
|
old_visibility=viewp->getVisible();
|
||||||
|
|
||||||
|
if (old_visibility!=new_visibility)
|
||||||
|
{
|
||||||
|
LLViewerEventRecorder::instance().logVisibilityChange( viewp->getPathname(), viewp->getName(), new_visibility,"widget");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (old_visibility)
|
||||||
{
|
{
|
||||||
viewp->handleVisibilityChange ( new_visibility );
|
viewp->handleVisibilityChange ( new_visibility );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Consider changing returns to confirm success and know which widget grabbed it
|
||||||
|
// For now assume success and log at highest xui possible
|
||||||
|
// NOTE we log actual state - which may differ if it somehow failed to set visibility
|
||||||
|
lldebugs << "LLView::handleVisibilityChange - now: " << getVisible() << " xui: " << viewp->getPathname() << " name: " << viewp->getName() << llendl;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -697,6 +713,7 @@ bool LLView::visibleEnabledAndContains(S32 local_x, S32 local_y)
|
||||||
&& getEnabled();
|
&& getEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is NOT event recording related
|
||||||
void LLView::logMouseEvent()
|
void LLView::logMouseEvent()
|
||||||
{
|
{
|
||||||
if (sDebugMouseHandling)
|
if (sDebugMouseHandling)
|
||||||
|
|
@ -743,7 +760,14 @@ LLView* LLView::childrenHandleMouseEvent(const METHOD& method, S32 x, S32 y, XDA
|
||||||
if ((viewp->*method)( local_x, local_y, extra )
|
if ((viewp->*method)( local_x, local_y, extra )
|
||||||
|| (allow_mouse_block && viewp->blockMouseEvent( local_x, local_y )))
|
|| (allow_mouse_block && viewp->blockMouseEvent( local_x, local_y )))
|
||||||
{
|
{
|
||||||
|
lldebugs << "LLView::childrenHandleMouseEvent calling updatemouseeventinfo - local_x|global x "<< local_x << " " << x << "local/global y " << local_y << " " << y << llendl;
|
||||||
|
lldebugs << "LLView::childrenHandleMouseEvent getPathname for viewp result: " << viewp->getPathname() << "for this view: " << getPathname() << llendl;
|
||||||
|
|
||||||
|
LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname());
|
||||||
|
|
||||||
|
// This is NOT event recording related
|
||||||
viewp->logMouseEvent();
|
viewp->logMouseEvent();
|
||||||
|
|
||||||
return viewp;
|
return viewp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -766,6 +790,7 @@ LLView* LLView::childrenHandleToolTip(S32 x, S32 y, MASK mask)
|
||||||
if (viewp->handleToolTip(local_x, local_y, mask)
|
if (viewp->handleToolTip(local_x, local_y, mask)
|
||||||
|| viewp->blockMouseEvent(local_x, local_y))
|
|| viewp->blockMouseEvent(local_x, local_y))
|
||||||
{
|
{
|
||||||
|
// This is NOT event recording related
|
||||||
viewp->logMouseEvent();
|
viewp->logMouseEvent();
|
||||||
return viewp;
|
return viewp;
|
||||||
}
|
}
|
||||||
|
|
@ -824,6 +849,7 @@ LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask)
|
||||||
if (viewp->handleHover(local_x, local_y, mask)
|
if (viewp->handleHover(local_x, local_y, mask)
|
||||||
|| viewp->blockMouseEvent(local_x, local_y))
|
|| viewp->blockMouseEvent(local_x, local_y))
|
||||||
{
|
{
|
||||||
|
// This is NOT event recording related
|
||||||
viewp->logMouseEvent();
|
viewp->logMouseEvent();
|
||||||
return viewp;
|
return viewp;
|
||||||
}
|
}
|
||||||
|
|
@ -907,10 +933,12 @@ BOOL LLView::handleKey(KEY key, MASK mask, BOOL called_from_parent)
|
||||||
|
|
||||||
if (!handled)
|
if (!handled)
|
||||||
{
|
{
|
||||||
|
// For event logging we don't care which widget handles it
|
||||||
|
// So we capture the key at the end of this function once we know if it was handled
|
||||||
handled = handleKeyHere( key, mask );
|
handled = handleKeyHere( key, mask );
|
||||||
if (handled && LLView::sDebugKeys)
|
if (handled)
|
||||||
{
|
{
|
||||||
llinfos << "Key handled by " << getName() << llendl;
|
llwarns << "Key handled by " << getName() << llendl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -958,6 +986,11 @@ BOOL LLView::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
|
||||||
handled = mParentView->handleUnicodeChar(uni_char, FALSE);
|
handled = mParentView->handleUnicodeChar(uni_char, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (handled)
|
||||||
|
{
|
||||||
|
LLViewerEventRecorder::instance().logKeyUnicodeEvent(uni_char);
|
||||||
|
}
|
||||||
|
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -987,12 +1020,16 @@ BOOL LLView::hasMouseCapture()
|
||||||
|
|
||||||
BOOL LLView::handleMouseUp(S32 x, S32 y, MASK mask)
|
BOOL LLView::handleMouseUp(S32 x, S32 y, MASK mask)
|
||||||
{
|
{
|
||||||
return childrenHandleMouseUp( x, y, mask ) != NULL;
|
LLView* r = childrenHandleMouseUp( x, y, mask );
|
||||||
|
|
||||||
|
return (r!=NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL LLView::handleMouseDown(S32 x, S32 y, MASK mask)
|
BOOL LLView::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||||
{
|
{
|
||||||
return childrenHandleMouseDown( x, y, mask ) != NULL;
|
LLView* r= childrenHandleMouseDown(x, y, mask );
|
||||||
|
|
||||||
|
return (r!=NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL LLView::handleDoubleClick(S32 x, S32 y, MASK mask)
|
BOOL LLView::handleDoubleClick(S32 x, S32 y, MASK mask)
|
||||||
|
|
@ -1065,7 +1102,7 @@ LLView* LLView::childrenHandleDoubleClick(S32 x, S32 y, MASK mask)
|
||||||
|
|
||||||
LLView* LLView::childrenHandleMouseUp(S32 x, S32 y, MASK mask)
|
LLView* LLView::childrenHandleMouseUp(S32 x, S32 y, MASK mask)
|
||||||
{
|
{
|
||||||
return childrenHandleMouseEvent(&LLView::handleMouseUp, x, y, mask);
|
return childrenHandleMouseEvent(&LLView::handleMouseUp, x, y, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLView* LLView::childrenHandleRightMouseUp(S32 x, S32 y, MASK mask)
|
LLView* LLView::childrenHandleRightMouseUp(S32 x, S32 y, MASK mask)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,296 @@
|
||||||
|
/**
|
||||||
|
* @file llviewereventrecorder.cpp
|
||||||
|
* @brief Viewer event recording and playback support for mouse and keyboard events
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Linden Research, Inc.
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation;
|
||||||
|
* version 2.1 of the License only.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
|
* $/LicenseInfo$
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "llviewereventrecorder.h"
|
||||||
|
#include "llui.h"
|
||||||
|
#include "llleap.h"
|
||||||
|
|
||||||
|
LLViewerEventRecorder::LLViewerEventRecorder() {
|
||||||
|
|
||||||
|
clear(UNDEFINED);
|
||||||
|
|
||||||
|
// Remove any previous event log file
|
||||||
|
std::string old_log_ui_events_to_llsd_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife_Events_log.old");
|
||||||
|
LLFile::remove(old_log_ui_events_to_llsd_file);
|
||||||
|
|
||||||
|
|
||||||
|
mLogFilename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife_Events_log.llsd");
|
||||||
|
LLFile::rename(mLogFilename, old_log_ui_events_to_llsd_file);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LLViewerEventRecorder::displayViewerEventRecorderMenuItems() {
|
||||||
|
return LLUI::sSettingGroups["config"]->getBOOL("ShowEventRecorderMenuItems");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LLViewerEventRecorder::setEventLoggingOn() {
|
||||||
|
if (! mLog.is_open()) {
|
||||||
|
mLog.open(mLogFilename, llofstream::out);
|
||||||
|
}
|
||||||
|
logEvents=true;
|
||||||
|
lldebugs << "LLViewerEventRecorder::setEventLoggingOn event logging turned on" << llendl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLViewerEventRecorder::setEventLoggingOff() {
|
||||||
|
logEvents=false;
|
||||||
|
mLog.flush();
|
||||||
|
mLog.close();
|
||||||
|
lldebugs << "LLViewerEventRecorder::setEventLoggingOff event logging turned off" << llendl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LLViewerEventRecorder::~LLViewerEventRecorder() {
|
||||||
|
if (mLog.is_open()) {
|
||||||
|
mLog.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLViewerEventRecorder::clear_xui() {
|
||||||
|
xui.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLViewerEventRecorder::clear(S32 r) {
|
||||||
|
|
||||||
|
xui.clear();
|
||||||
|
|
||||||
|
local_x=r;
|
||||||
|
local_y=r;
|
||||||
|
|
||||||
|
global_x=r;
|
||||||
|
global_y=r;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLViewerEventRecorder::setMouseLocalCoords(S32 x, S32 y) {
|
||||||
|
local_x=x;
|
||||||
|
local_y=y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLViewerEventRecorder::setMouseGlobalCoords(S32 x, S32 y) {
|
||||||
|
global_x=x;
|
||||||
|
global_y=y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLViewerEventRecorder::updateMouseEventInfo(S32 local_x, S32 local_y, S32 global_x, S32 global_y, std::string mName) {
|
||||||
|
|
||||||
|
LLView * target_view = LLUI::resolvePath(LLUI::getRootView(), xui);
|
||||||
|
if (! target_view) {
|
||||||
|
lldebugs << "LLViewerEventRecorder::updateMouseEventInfo - xui path on file at moment is NOT valid - so DO NOT record these local coords" << llendl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lldebugs << "LLViewerEventRecorder::updateMouseEventInfo b4 updatemouseeventinfo - local_x|global x "<< this->local_x << " " << this->global_x << "local/global y " << this->local_y << " " << this->global_y << " mname: " << mName << " xui: " << xui << llendl;
|
||||||
|
|
||||||
|
|
||||||
|
if (this->local_x < 1 && this->local_y<1 && local_x && local_y) {
|
||||||
|
this->local_x=local_x;
|
||||||
|
this->local_y=local_y;
|
||||||
|
}
|
||||||
|
this->global_x=global_x;
|
||||||
|
this->global_y=global_y;
|
||||||
|
|
||||||
|
// ONLY record deepest xui path for hierarchy searches - or first/only xui for floaters/panels reached via mouse captor - and llmousehandler
|
||||||
|
if (mName!="" && mName!="/" && xui=="") {
|
||||||
|
// xui=std::string("/")+mName+xui;
|
||||||
|
//xui=mName+xui;
|
||||||
|
xui = mName; // TODO review confirm we never call with partial path - also cAN REMOVE CHECK FOR "" - ON OTHER HAND IT'S PRETTY HARMLESS
|
||||||
|
}
|
||||||
|
|
||||||
|
lldebugs << "LLViewerEventRecorder::updateMouseEventInfo after updatemouseeventinfo - local_x|global x "<< this->local_x << " " << this->global_x << "local/global y " << this->local_y << " " << this->global_y << " mname: " << mName << " xui: " << xui << llendl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLViewerEventRecorder::logVisibilityChange(std::string xui, std::string name, BOOL visibility, std::string event_subtype) {
|
||||||
|
|
||||||
|
LLSD event=LLSD::emptyMap();
|
||||||
|
|
||||||
|
event.insert("event",LLSD(std::string("visibility")));
|
||||||
|
|
||||||
|
if (visibility) {
|
||||||
|
event.insert("visibility",LLSD(true));
|
||||||
|
} else {
|
||||||
|
event.insert("visibility",LLSD(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event_subtype!="") {
|
||||||
|
event.insert("event_subtype", LLSD(event_subtype));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(name!="") {
|
||||||
|
event.insert("name",LLSD(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xui!="") {
|
||||||
|
event.insert("path",LLSD(xui));
|
||||||
|
}
|
||||||
|
|
||||||
|
event.insert("timestamp",LLSD(LLDate::now().asString()));
|
||||||
|
recordEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string LLViewerEventRecorder::get_xui() {
|
||||||
|
return xui;
|
||||||
|
}
|
||||||
|
void LLViewerEventRecorder::update_xui(std::string xui) {
|
||||||
|
if (xui!="" && this->xui=="" ) {
|
||||||
|
lldebugs << "LLViewerEventRecorder::update_xui to " << xui << llendl;
|
||||||
|
this->xui=xui;
|
||||||
|
} else {
|
||||||
|
lldebugs << "LLViewerEventRecorder::update_xui called with empty string" << llendl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLViewerEventRecorder::logKeyEvent(KEY key, MASK mask) {
|
||||||
|
|
||||||
|
// NOTE: Event recording only logs keydown events - the viewer itself hides keyup events at a fairly low level in the code and does not appear to care about them anywhere
|
||||||
|
|
||||||
|
LLSD event = LLSD::emptyMap();
|
||||||
|
|
||||||
|
event.insert("event",LLSD("type"));
|
||||||
|
|
||||||
|
// keysym ...or
|
||||||
|
// keycode...or
|
||||||
|
// char
|
||||||
|
event.insert("keysym",LLSD(LLKeyboard::stringFromKey(key)));
|
||||||
|
|
||||||
|
// path (optional) - for now we are not recording path for key events during record - should not be needed for full record and playback of recorded steps
|
||||||
|
// as a vita script - it does become useful if you edit the resulting vita script and wish to remove some steps leading to a key event - that sort of edit might
|
||||||
|
// break the test script and it would be useful to have more context to make these sorts of edits safer
|
||||||
|
|
||||||
|
// TODO replace this with a call which extracts to an array of names of masks (just like vita expects during playback)
|
||||||
|
// This is looking more and more like an object is a good idea, for this part a handy method call to setMask(mask) would be nice :-)
|
||||||
|
// call the func - llkeyboard::llsdStringarrayFromMask
|
||||||
|
|
||||||
|
LLSD key_mask=LLSD::emptyArray();
|
||||||
|
|
||||||
|
if (mask & MASK_CONTROL) { key_mask.append(LLSD("CTL")); } // Mac command key - has code of 0x1 in llcommon/indra_contstants
|
||||||
|
if (mask & MASK_ALT) { key_mask.append(LLSD("ALT")); }
|
||||||
|
if (mask & MASK_SHIFT) { key_mask.append(LLSD("SHIFT")); }
|
||||||
|
if (mask & MASK_MAC_CONTROL) { key_mask.append(LLSD("MAC_CONTROL")); }
|
||||||
|
|
||||||
|
event.insert("mask",key_mask);
|
||||||
|
event.insert("timestamp",LLSD(LLDate::now().asString()));
|
||||||
|
|
||||||
|
// Although vita has keyDown and keyUp requests it does not have type as a high-level concept
|
||||||
|
// (maybe it should) - instead it has a convenience method that generates the keydown and keyup events
|
||||||
|
// Here we will use "type" as our event type
|
||||||
|
|
||||||
|
lldebugs << "LLVIewerEventRecorder::logKeyEvent Serialized LLSD for event " << event.asString() << "\n" << llendl;
|
||||||
|
|
||||||
|
|
||||||
|
//lldebugs << "[VITA] key_name: " << LLKeyboard::stringFromKey(key) << "mask: "<< mask << "handled by " << getName() << llendl;
|
||||||
|
lldebugs << "LLVIewerEventRecorder::logKeyEvent key_name: " << LLKeyboard::stringFromKey(key) << "mask: "<< mask << llendl;
|
||||||
|
|
||||||
|
|
||||||
|
recordEvent(event);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLViewerEventRecorder::playbackRecording() {
|
||||||
|
|
||||||
|
LLSD LeapCommand;
|
||||||
|
|
||||||
|
// ivita sets this on startup, it also sends commands to the viewer to make start, stop, and playback menu items visible in viewer
|
||||||
|
LeapCommand =LLUI::sSettingGroups["config"]->getLLSD("LeapPlaybackEventsCommand");
|
||||||
|
|
||||||
|
lldebugs << "[VITA] launching playback - leap command is: " << LLSDXMLStreamer(LeapCommand) << llendl;
|
||||||
|
LLLeap::create("", LeapCommand, false); // exception=false
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LLViewerEventRecorder::recordEvent(LLSD event) {
|
||||||
|
lldebugs << "LLViewerEventRecorder::recordEvent event written to log: " << LLSDXMLStreamer(event) << llendl;
|
||||||
|
mLog << event << std::endl;
|
||||||
|
|
||||||
|
}
|
||||||
|
void LLViewerEventRecorder::logKeyUnicodeEvent(llwchar uni_char) {
|
||||||
|
if (! logEvents) return;
|
||||||
|
|
||||||
|
// Note: keyUp is not captured since the viewer seems to not care about keyUp events
|
||||||
|
|
||||||
|
LLSD event=LLSD::emptyMap();
|
||||||
|
|
||||||
|
event.insert("timestamp",LLSD(LLDate::now().asString()));
|
||||||
|
|
||||||
|
|
||||||
|
// keysym ...or
|
||||||
|
// keycode...or
|
||||||
|
// char
|
||||||
|
|
||||||
|
lldebugs << "Wrapped in conversion to wstring " << wstring_to_utf8str(LLWString( 1, uni_char)) << "\n" << llendl;
|
||||||
|
|
||||||
|
event.insert("char",
|
||||||
|
LLSD( wstring_to_utf8str(LLWString( 1,uni_char)) )
|
||||||
|
);
|
||||||
|
|
||||||
|
// path (optional) - for now we are not recording path for key events during record - should not be needed for full record and playback of recorded steps
|
||||||
|
// as a vita script - it does become useful if you edit the resulting vita script and wish to remove some steps leading to a key event - that sort of edit might
|
||||||
|
// break the test script and it would be useful to have more context to make these sorts of edits safer
|
||||||
|
|
||||||
|
// TODO need to consider mask keys too? Doesn't seem possible - at least not easily at this point
|
||||||
|
|
||||||
|
event.insert("event",LLSD("keyDown"));
|
||||||
|
|
||||||
|
lldebugs << "[VITA] unicode key: " << uni_char << llendl;
|
||||||
|
lldebugs << "[VITA] dumpxml " << LLSDXMLStreamer(event) << "\n" << llendl;
|
||||||
|
|
||||||
|
|
||||||
|
recordEvent(event);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLViewerEventRecorder::logMouseEvent(std::string button_state,std::string button_name)
|
||||||
|
{
|
||||||
|
if (! logEvents) return;
|
||||||
|
|
||||||
|
LLSD event=LLSD::emptyMap();
|
||||||
|
|
||||||
|
event.insert("event",LLSD(std::string("mouse"+ button_state)));
|
||||||
|
event.insert("button",LLSD(button_name));
|
||||||
|
if (xui!="") {
|
||||||
|
event.insert("path",LLSD(xui));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (local_x>0 && local_y>0) {
|
||||||
|
event.insert("local_x",LLSD(local_x));
|
||||||
|
event.insert("local_y",LLSD(local_y));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (global_x>0 && global_y>0) {
|
||||||
|
event.insert("global_x",LLSD(global_x));
|
||||||
|
event.insert("global_y",LLSD(global_y));
|
||||||
|
}
|
||||||
|
event.insert("timestamp",LLSD(LLDate::now().asString()));
|
||||||
|
recordEvent(event);
|
||||||
|
|
||||||
|
|
||||||
|
clear(UNDEFINED);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
/**
|
||||||
|
* @file llviewereventrecorder.h
|
||||||
|
* @brief Viewer event recording and playback support for mouse and keyboard events
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, Linden Research, Inc.
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation;
|
||||||
|
* version 2.1 of the License only.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
|
* $/LicenseInfo$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LL_VIEWER_EVENT_RECORDER
|
||||||
|
#define LL_VIEWER_EVENT_RECORDER
|
||||||
|
|
||||||
|
|
||||||
|
#include "linden_common.h"
|
||||||
|
|
||||||
|
#include "lldir.h"
|
||||||
|
#include "llsd.h"
|
||||||
|
#include "llfile.h"
|
||||||
|
#include "llvfile.h"
|
||||||
|
#include "lldate.h"
|
||||||
|
#include "llsdserialize.h"
|
||||||
|
#include "llkeyboard.h"
|
||||||
|
#include "llstring.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "llsingleton.h" // includes llerror which we need here so we can skip the include here
|
||||||
|
|
||||||
|
class LLViewerEventRecorder : public LLSingleton<LLViewerEventRecorder>
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
LLViewerEventRecorder(); // TODO Protect constructor better if we can (not happy in private section) - could add a factory... - we are singleton
|
||||||
|
~LLViewerEventRecorder();
|
||||||
|
|
||||||
|
|
||||||
|
void updateMouseEventInfo(S32 local_x,S32 local_y, S32 global_x, S32 global_y, std::string mName);
|
||||||
|
void setMouseLocalCoords(S32 x,S32 y);
|
||||||
|
void setMouseGlobalCoords(S32 x,S32 y);
|
||||||
|
|
||||||
|
void logMouseEvent(std::string button_state, std::string button_name );
|
||||||
|
void logKeyEvent(KEY key, MASK mask);
|
||||||
|
void logKeyUnicodeEvent(llwchar uni_char);
|
||||||
|
|
||||||
|
void logVisibilityChange(std::string xui, std::string name, BOOL visibility, std::string event_subtype);
|
||||||
|
|
||||||
|
void clear_xui();
|
||||||
|
std::string get_xui();
|
||||||
|
void update_xui(std::string xui);
|
||||||
|
|
||||||
|
bool getLoggingStatus();
|
||||||
|
void setEventLoggingOn();
|
||||||
|
void setEventLoggingOff();
|
||||||
|
|
||||||
|
void playbackRecording();
|
||||||
|
|
||||||
|
bool displayViewerEventRecorderMenuItems();
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// On if we wish to log events at the moment - toggle via Develop/Recorder submenu
|
||||||
|
bool logEvents;
|
||||||
|
|
||||||
|
std::string mLogFilename;
|
||||||
|
llofstream mLog;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Mouse event info
|
||||||
|
S32 global_x;
|
||||||
|
S32 global_y;
|
||||||
|
S32 local_x;
|
||||||
|
S32 local_y;
|
||||||
|
|
||||||
|
// XUI path of UI element
|
||||||
|
std::string xui;
|
||||||
|
|
||||||
|
// Actually write the event out to llsd log file
|
||||||
|
void recordEvent(LLSD event);
|
||||||
|
|
||||||
|
void clear(S32 r);
|
||||||
|
|
||||||
|
static const S32 UNDEFINED=-1;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
@ -122,6 +122,7 @@ void LLWindowCallbacks::handleResize(LLWindow *window, const S32 width, const S3
|
||||||
|
|
||||||
void LLWindowCallbacks::handleFocus(LLWindow *window)
|
void LLWindowCallbacks::handleFocus(LLWindow *window)
|
||||||
{
|
{
|
||||||
|
LL_WARNS("COCOA") << "Called handleFocus proto" << LL_ENDL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLWindowCallbacks::handleFocusLost(LLWindow *window)
|
void LLWindowCallbacks::handleFocusLost(LLWindow *window)
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,9 @@
|
||||||
* $/LicenseInfo$
|
* $/LicenseInfo$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef LL_LLWINDOWMACOSX_OBJC_H
|
||||||
|
#define LL_LLWINDOWMACOSX_OBJC_H
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -144,3 +147,5 @@ NSWindowRef getMainAppWindow();
|
||||||
GLViewRef getGLView();
|
GLViewRef getGLView();
|
||||||
|
|
||||||
unsigned int getModifiers();
|
unsigned int getModifiers();
|
||||||
|
|
||||||
|
#endif // LL_LLWINDOWMACOSX_OBJC_H
|
||||||
|
|
|
||||||
|
|
@ -331,7 +331,16 @@ void callMouseExit()
|
||||||
|
|
||||||
void callWindowFocus()
|
void callWindowFocus()
|
||||||
{
|
{
|
||||||
gWindowImplementation->getCallbacks()->handleFocus(gWindowImplementation);
|
if ( gWindowImplementation && gWindowImplementation->getCallbacks() )
|
||||||
|
{
|
||||||
|
gWindowImplementation->getCallbacks()->handleFocus (gWindowImplementation);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LL_WARNS("COCOA") << "Window Implementation or callbacks not yet initialized." << LL_ENDL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void callWindowUnfocus()
|
void callWindowUnfocus()
|
||||||
|
|
@ -1300,6 +1309,8 @@ void LLWindowMacOSX::setupFailure(const std::string& text, const std::string& ca
|
||||||
OSMessageBox(text, caption, type);
|
OSMessageBox(text, caption, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note on event recording - QUIT is a known special case and we are choosing NOT to record it for the record and playback feature
|
||||||
|
// it is handled at a very low-level
|
||||||
const char* cursorIDToName(int id)
|
const char* cursorIDToName(int id)
|
||||||
{
|
{
|
||||||
switch (id)
|
switch (id)
|
||||||
|
|
|
||||||
|
|
@ -391,7 +391,7 @@ LLControlVariable* LLControlGroup::declareControl(const std::string& name, eCont
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
llwarns << "Control named " << name << " already exists, ignoring new declaration." << llendl;
|
LL_WARNS("Settings") << "Control named " << name << " already exists, ignoring new declaration." << LL_ENDL;
|
||||||
}
|
}
|
||||||
return existing_control;
|
return existing_control;
|
||||||
}
|
}
|
||||||
|
|
@ -630,14 +630,14 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require
|
||||||
|
|
||||||
if (!xml_controls.parseFile(filename))
|
if (!xml_controls.parseFile(filename))
|
||||||
{
|
{
|
||||||
llwarns << "Unable to open control file " << filename << llendl;
|
LL_WARNS("Settings") << "Unable to open control file " << filename << LL_ENDL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLXmlTreeNode* rootp = xml_controls.getRoot();
|
LLXmlTreeNode* rootp = xml_controls.getRoot();
|
||||||
if (!rootp || !rootp->hasAttribute("version"))
|
if (!rootp || !rootp->hasAttribute("version"))
|
||||||
{
|
{
|
||||||
llwarns << "No valid settings header found in control file " << filename << llendl;
|
LL_WARNS("Settings") << "No valid settings header found in control file " << filename << LL_ENDL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -650,7 +650,7 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require
|
||||||
// Check file version
|
// Check file version
|
||||||
if (version != CURRENT_VERSION)
|
if (version != CURRENT_VERSION)
|
||||||
{
|
{
|
||||||
llinfos << filename << " does not appear to be a version " << CURRENT_VERSION << " controls file" << llendl;
|
LL_INFOS("Settings") << filename << " does not appear to be a version " << CURRENT_VERSION << " controls file" << LL_ENDL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -668,7 +668,7 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require
|
||||||
if (!name.empty())
|
if (!name.empty())
|
||||||
{
|
{
|
||||||
//read in to end of line
|
//read in to end of line
|
||||||
llwarns << "LLControlGroup::loadFromFile() : Trying to set \"" << name << "\", setting doesn't exist." << llendl;
|
LL_WARNS("Settings") << "LLControlGroup::loadFromFile() : Trying to set \"" << name << "\", setting doesn't exist." << LL_ENDL;
|
||||||
}
|
}
|
||||||
child_nodep = rootp->getNextChild();
|
child_nodep = rootp->getNextChild();
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -822,7 +822,7 @@ U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only
|
||||||
LLControlVariable* control = iter->second;
|
LLControlVariable* control = iter->second;
|
||||||
if (!control)
|
if (!control)
|
||||||
{
|
{
|
||||||
llwarns << "Tried to save invalid control: " << iter->first << llendl;
|
LL_WARNS("Settings") << "Tried to save invalid control: " << iter->first << LL_ENDL;
|
||||||
}
|
}
|
||||||
else if( control->shouldSave(nondefault_only) )
|
else if( control->shouldSave(nondefault_only) )
|
||||||
{
|
{
|
||||||
|
|
@ -838,12 +838,12 @@ U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only
|
||||||
{
|
{
|
||||||
LLSDSerialize::toPrettyXML(settings, file);
|
LLSDSerialize::toPrettyXML(settings, file);
|
||||||
file.close();
|
file.close();
|
||||||
llinfos << "Saved to " << filename << llendl;
|
LL_INFOS("Settings") << "Saved to " << filename << LL_ENDL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// This is a warning because sometime we want to use settings files which can't be written...
|
// This is a warning because sometime we want to use settings files which can't be written...
|
||||||
llwarns << "Unable to open settings file: " << filename << llendl;
|
LL_WARNS("Settings") << "Unable to open settings file: " << filename << LL_ENDL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return num_saved;
|
return num_saved;
|
||||||
|
|
@ -856,14 +856,14 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v
|
||||||
infile.open(filename);
|
infile.open(filename);
|
||||||
if(!infile.is_open())
|
if(!infile.is_open())
|
||||||
{
|
{
|
||||||
llwarns << "Cannot find file " << filename << " to load." << llendl;
|
LL_WARNS("Settings") << "Cannot find file " << filename << " to load." << LL_ENDL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(settings, infile))
|
if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(settings, infile))
|
||||||
{
|
{
|
||||||
infile.close();
|
infile.close();
|
||||||
llwarns << "Unable to parse LLSD control file " << filename << ". Trying Legacy Method." << llendl;
|
LL_WARNS("Settings") << "Unable to parse LLSD control file " << filename << ". Trying Legacy Method." << LL_ENDL;
|
||||||
return loadFromFileLegacy(filename, TRUE, TYPE_STRING);
|
return loadFromFileLegacy(filename, TRUE, TYPE_STRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -976,6 +976,7 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v
|
||||||
++validitems;
|
++validitems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LL_DEBUGS("Settings") << "Loaded " << validitems << " settings from " << filename << LL_ENDL;
|
||||||
return validitems;
|
return validitems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1012,7 +1013,7 @@ void main()
|
||||||
BOOL_CONTROL baz;
|
BOOL_CONTROL baz;
|
||||||
|
|
||||||
U32 count = gGlobals.loadFromFile("controls.ini");
|
U32 count = gGlobals.loadFromFile("controls.ini");
|
||||||
llinfos << "Loaded " << count << " controls" << llendl;
|
LL_INFOS("Settings") << "Loaded " << count << " controls" << LL_ENDL;
|
||||||
|
|
||||||
// test insertion
|
// test insertion
|
||||||
foo = new LLControlVariable<F32>("gFoo", 5.f, 1.f, 20.f);
|
foo = new LLControlVariable<F32>("gFoo", 5.f, 1.f, 20.f);
|
||||||
|
|
@ -1273,19 +1274,19 @@ LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, const st
|
||||||
LLColor4 color(sd);
|
LLColor4 color(sd);
|
||||||
if (color.mV[VRED] < 0.f || color.mV[VRED] > 1.f)
|
if (color.mV[VRED] < 0.f || color.mV[VRED] > 1.f)
|
||||||
{
|
{
|
||||||
llwarns << "Color " << control_name << " red value out of range: " << color << llendl;
|
LL_WARNS("Settings") << "Color " << control_name << " red value out of range: " << color << LL_ENDL;
|
||||||
}
|
}
|
||||||
else if (color.mV[VGREEN] < 0.f || color.mV[VGREEN] > 1.f)
|
else if (color.mV[VGREEN] < 0.f || color.mV[VGREEN] > 1.f)
|
||||||
{
|
{
|
||||||
llwarns << "Color " << control_name << " green value out of range: " << color << llendl;
|
LL_WARNS("Settings") << "Color " << control_name << " green value out of range: " << color << LL_ENDL;
|
||||||
}
|
}
|
||||||
else if (color.mV[VBLUE] < 0.f || color.mV[VBLUE] > 1.f)
|
else if (color.mV[VBLUE] < 0.f || color.mV[VBLUE] > 1.f)
|
||||||
{
|
{
|
||||||
llwarns << "Color " << control_name << " blue value out of range: " << color << llendl;
|
LL_WARNS("Settings") << "Color " << control_name << " blue value out of range: " << color << LL_ENDL;
|
||||||
}
|
}
|
||||||
else if (color.mV[VALPHA] < 0.f || color.mV[VALPHA] > 1.f)
|
else if (color.mV[VALPHA] < 0.f || color.mV[VALPHA] > 1.f)
|
||||||
{
|
{
|
||||||
llwarns << "Color " << control_name << " alpha value out of range: " << color << llendl;
|
LL_WARNS("Settings") << "Color " << control_name << " alpha value out of range: " << color << LL_ENDL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return LLColor4(sd);
|
return LLColor4(sd);
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,7 @@ set(viewer_SOURCE_FILES
|
||||||
llexpandabletextbox.cpp
|
llexpandabletextbox.cpp
|
||||||
llexternaleditor.cpp
|
llexternaleditor.cpp
|
||||||
llface.cpp
|
llface.cpp
|
||||||
|
llfacebookconnect.cpp
|
||||||
llfasttimerview.cpp
|
llfasttimerview.cpp
|
||||||
llfavoritesbar.cpp
|
llfavoritesbar.cpp
|
||||||
llfeaturemanager.cpp
|
llfeaturemanager.cpp
|
||||||
|
|
@ -273,6 +274,7 @@ set(viewer_SOURCE_FILES
|
||||||
llfloatersettingsdebug.cpp
|
llfloatersettingsdebug.cpp
|
||||||
llfloatersidepanelcontainer.cpp
|
llfloatersidepanelcontainer.cpp
|
||||||
llfloatersnapshot.cpp
|
llfloatersnapshot.cpp
|
||||||
|
llfloatersocial.cpp
|
||||||
llfloatersounddevices.cpp
|
llfloatersounddevices.cpp
|
||||||
llfloaterspellchecksettings.cpp
|
llfloaterspellchecksettings.cpp
|
||||||
llfloatertelehub.cpp
|
llfloatertelehub.cpp
|
||||||
|
|
@ -508,6 +510,7 @@ set(viewer_SOURCE_FILES
|
||||||
llsidetraypanelcontainer.cpp
|
llsidetraypanelcontainer.cpp
|
||||||
llsky.cpp
|
llsky.cpp
|
||||||
llslurl.cpp
|
llslurl.cpp
|
||||||
|
llsnapshotlivepreview.cpp
|
||||||
llspatialpartition.cpp
|
llspatialpartition.cpp
|
||||||
llspeakers.cpp
|
llspeakers.cpp
|
||||||
llspeakingindicatormanager.cpp
|
llspeakingindicatormanager.cpp
|
||||||
|
|
@ -776,6 +779,7 @@ set(viewer_HEADER_FILES
|
||||||
llexpandabletextbox.h
|
llexpandabletextbox.h
|
||||||
llexternaleditor.h
|
llexternaleditor.h
|
||||||
llface.h
|
llface.h
|
||||||
|
llfacebookconnect.h
|
||||||
llfasttimerview.h
|
llfasttimerview.h
|
||||||
llfavoritesbar.h
|
llfavoritesbar.h
|
||||||
llfeaturemanager.h
|
llfeaturemanager.h
|
||||||
|
|
@ -858,6 +862,7 @@ set(viewer_HEADER_FILES
|
||||||
llfloatersettingsdebug.h
|
llfloatersettingsdebug.h
|
||||||
llfloatersidepanelcontainer.h
|
llfloatersidepanelcontainer.h
|
||||||
llfloatersnapshot.h
|
llfloatersnapshot.h
|
||||||
|
llfloatersocial.h
|
||||||
llfloatersounddevices.h
|
llfloatersounddevices.h
|
||||||
llfloaterspellchecksettings.h
|
llfloaterspellchecksettings.h
|
||||||
llfloatertelehub.h
|
llfloatertelehub.h
|
||||||
|
|
@ -1082,6 +1087,7 @@ set(viewer_HEADER_FILES
|
||||||
llsidetraypanelcontainer.h
|
llsidetraypanelcontainer.h
|
||||||
llsky.h
|
llsky.h
|
||||||
llslurl.h
|
llslurl.h
|
||||||
|
llsnapshotlivepreview.h
|
||||||
llspatialpartition.h
|
llspatialpartition.h
|
||||||
llspeakers.h
|
llspeakers.h
|
||||||
llspeakingindicatormanager.h
|
llspeakingindicatormanager.h
|
||||||
|
|
|
||||||
|
|
@ -260,6 +260,16 @@
|
||||||
is_running_function="Floater.IsOpen"
|
is_running_function="Floater.IsOpen"
|
||||||
is_running_parameters="snapshot"
|
is_running_parameters="snapshot"
|
||||||
/>
|
/>
|
||||||
|
<command name="social"
|
||||||
|
available_in_toybox="true"
|
||||||
|
icon="Command_Social_Icon"
|
||||||
|
label_ref="Command_Social_Label"
|
||||||
|
tooltip_ref="Command_Social_Tooltip"
|
||||||
|
execute_function="Floater.ToggleOrBringToFront"
|
||||||
|
execute_parameters="social"
|
||||||
|
is_running_function="Floater.IsOpen"
|
||||||
|
is_running_parameters="social"
|
||||||
|
/>
|
||||||
<command name="speak"
|
<command name="speak"
|
||||||
available_in_toybox="true"
|
available_in_toybox="true"
|
||||||
icon="Command_Speak_Icon"
|
icon="Command_Speak_Icon"
|
||||||
|
|
|
||||||
|
|
@ -4952,6 +4952,16 @@
|
||||||
<key>Value</key>
|
<key>Value</key>
|
||||||
<array />
|
<array />
|
||||||
</map>
|
</map>
|
||||||
|
<key>LeapPlaybackEventsCommand</key>
|
||||||
|
<map>
|
||||||
|
<key>Comment</key>
|
||||||
|
<string>Command line to use leap to launch playback of event recordings</string>
|
||||||
|
<key>Persist</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>Type</key>
|
||||||
|
<string>LLSD</string>
|
||||||
|
<key>Value</key>
|
||||||
|
</map>
|
||||||
<key>LSLFindCaseInsensitivity</key>
|
<key>LSLFindCaseInsensitivity</key>
|
||||||
<map>
|
<map>
|
||||||
<key>Comment</key>
|
<key>Comment</key>
|
||||||
|
|
@ -9862,7 +9872,7 @@
|
||||||
<key>RenderUseVAO</key>
|
<key>RenderUseVAO</key>
|
||||||
<map>
|
<map>
|
||||||
<key>Comment</key>
|
<key>Comment</key>
|
||||||
<string>[EXPERIMENTAL] Use GL Vertex Array Objects</string>
|
<string>[EXPERIMENTAL] Use GL Vertex Array Objects.</string>
|
||||||
<key>Persist</key>
|
<key>Persist</key>
|
||||||
<integer>1</integer>
|
<integer>1</integer>
|
||||||
<key>Type</key>
|
<key>Type</key>
|
||||||
|
|
@ -10466,6 +10476,17 @@
|
||||||
<key>Value</key>
|
<key>Value</key>
|
||||||
<integer>0</integer>
|
<integer>0</integer>
|
||||||
</map>
|
</map>
|
||||||
|
<key>ShowEventRecorderMenuItems</key>
|
||||||
|
<map>
|
||||||
|
<key>Comment</key>
|
||||||
|
<string>Whether or not Event Recorder menu choices - Start / Stop event recording should appear in the (currently) Develop menu</string>
|
||||||
|
<key>Persist</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>Type</key>
|
||||||
|
<string>Boolean</string>
|
||||||
|
<key>Value</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</map>
|
||||||
<key>ShowGestureButton</key>
|
<key>ShowGestureButton</key>
|
||||||
<map>
|
<map>
|
||||||
<key>Comment</key>
|
<key>Comment</key>
|
||||||
|
|
@ -13106,6 +13127,17 @@
|
||||||
<key>Value</key>
|
<key>Value</key>
|
||||||
<integer>0</integer>
|
<integer>0</integer>
|
||||||
</map>
|
</map>
|
||||||
|
<key>SocialPhotoResolution</key>
|
||||||
|
<map>
|
||||||
|
<key>Comment</key>
|
||||||
|
<string>Default resolution when sharing photo using the social floater</string>
|
||||||
|
<key>Persist</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>Type</key>
|
||||||
|
<string>String</string>
|
||||||
|
<key>Value</key>
|
||||||
|
<string>[i800,i600]</string>
|
||||||
|
</map>
|
||||||
<key>sourceid</key>
|
<key>sourceid</key>
|
||||||
<map>
|
<map>
|
||||||
<key>Comment</key>
|
<key>Comment</key>
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
<command name="speak"/>
|
<command name="speak"/>
|
||||||
<command name="destinations"/>
|
<command name="destinations"/>
|
||||||
<command name="people"/>
|
<command name="people"/>
|
||||||
|
<command name="social"/>
|
||||||
<command name="profile"/>
|
<command name="profile"/>
|
||||||
<command name="move"/>
|
<command name="move"/>
|
||||||
<command name="view"/>
|
<command name="view"/>
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,11 @@ BOOL LLAgentUI::buildLocationString(std::string& str, ELocationFormat fmt,const
|
||||||
case LOCATION_FORMAT_NORMAL:
|
case LOCATION_FORMAT_NORMAL:
|
||||||
buffer = llformat("%s", region_name.c_str());
|
buffer = llformat("%s", region_name.c_str());
|
||||||
break;
|
break;
|
||||||
|
case LOCATION_FORMAT_NORMAL_COORDS:
|
||||||
|
buffer = llformat("%s (%d, %d, %d)",
|
||||||
|
region_name.c_str(),
|
||||||
|
pos_x, pos_y, pos_z);
|
||||||
|
break;
|
||||||
case LOCATION_FORMAT_NO_COORDS:
|
case LOCATION_FORMAT_NO_COORDS:
|
||||||
buffer = llformat("%s%s%s",
|
buffer = llformat("%s%s%s",
|
||||||
region_name.c_str(),
|
region_name.c_str(),
|
||||||
|
|
@ -143,6 +148,11 @@ BOOL LLAgentUI::buildLocationString(std::string& str, ELocationFormat fmt,const
|
||||||
case LOCATION_FORMAT_NORMAL:
|
case LOCATION_FORMAT_NORMAL:
|
||||||
buffer = llformat("%s, %s", parcel_name.c_str(), region_name.c_str());
|
buffer = llformat("%s, %s", parcel_name.c_str(), region_name.c_str());
|
||||||
break;
|
break;
|
||||||
|
case LOCATION_FORMAT_NORMAL_COORDS:
|
||||||
|
buffer = llformat("%s (%d, %d, %d)",
|
||||||
|
parcel_name.c_str(),
|
||||||
|
pos_x, pos_y, pos_z);
|
||||||
|
break;
|
||||||
case LOCATION_FORMAT_NO_MATURITY:
|
case LOCATION_FORMAT_NO_MATURITY:
|
||||||
buffer = llformat("%s, %s (%d, %d, %d)",
|
buffer = llformat("%s, %s (%d, %d, %d)",
|
||||||
parcel_name.c_str(),
|
parcel_name.c_str(),
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ public:
|
||||||
enum ELocationFormat
|
enum ELocationFormat
|
||||||
{
|
{
|
||||||
LOCATION_FORMAT_NORMAL, // Parcel
|
LOCATION_FORMAT_NORMAL, // Parcel
|
||||||
|
LOCATION_FORMAT_NORMAL_COORDS, // Parcel (x, y, z)
|
||||||
LOCATION_FORMAT_LANDMARK, // Parcel, Region
|
LOCATION_FORMAT_LANDMARK, // Parcel, Region
|
||||||
LOCATION_FORMAT_NO_MATURITY, // Parcel, Region (x, y, z)
|
LOCATION_FORMAT_NO_MATURITY, // Parcel, Region (x, y, z)
|
||||||
LOCATION_FORMAT_NO_COORDS, // Parcel, Region - Maturity
|
LOCATION_FORMAT_NO_COORDS, // Parcel, Region - Maturity
|
||||||
|
|
|
||||||
|
|
@ -1538,7 +1538,11 @@ void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj
|
||||||
std::set<LLUUID> requested_item_ids;
|
std::set<LLUUID> requested_item_ids;
|
||||||
std::set<LLUUID> current_item_ids;
|
std::set<LLUUID> current_item_ids;
|
||||||
for (S32 i=0; i<obj_item_array.count(); i++)
|
for (S32 i=0; i<obj_item_array.count(); i++)
|
||||||
requested_item_ids.insert(obj_item_array[i].get()->getLinkedUUID());
|
{
|
||||||
|
const LLUUID & requested_id = obj_item_array[i].get()->getLinkedUUID();
|
||||||
|
//llinfos << "Requested attachment id " << requested_id << llendl;
|
||||||
|
requested_item_ids.insert(requested_id);
|
||||||
|
}
|
||||||
|
|
||||||
// Build up list of objects to be removed and items currently attached.
|
// Build up list of objects to be removed and items currently attached.
|
||||||
llvo_vec_t objects_to_remove;
|
llvo_vec_t objects_to_remove;
|
||||||
|
|
@ -1555,16 +1559,27 @@ void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj
|
||||||
if (objectp)
|
if (objectp)
|
||||||
{
|
{
|
||||||
LLUUID object_item_id = objectp->getAttachmentItemID();
|
LLUUID object_item_id = objectp->getAttachmentItemID();
|
||||||
|
|
||||||
|
bool remove_attachment = true;
|
||||||
if (requested_item_ids.find(object_item_id) != requested_item_ids.end())
|
if (requested_item_ids.find(object_item_id) != requested_item_ids.end())
|
||||||
{
|
{ // Object currently worn, was requested to keep it
|
||||||
// Object currently worn, was requested.
|
|
||||||
// Flag as currently worn so we won't have to add it again.
|
// Flag as currently worn so we won't have to add it again.
|
||||||
current_item_ids.insert(object_item_id);
|
remove_attachment = false;
|
||||||
|
}
|
||||||
|
else if (objectp->isTempAttachment())
|
||||||
|
{ // Check if we should keep this temp attachment
|
||||||
|
remove_attachment = LLAppearanceMgr::instance().shouldRemoveTempAttachment(objectp->getID());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remove_attachment)
|
||||||
|
{
|
||||||
|
// llinfos << "found object to remove, id " << objectp->getID() << ", item " << objectp->getAttachmentItemID() << llendl;
|
||||||
|
objects_to_remove.push_back(objectp);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// object currently worn, not requested.
|
// llinfos << "found object to keep, id " << objectp->getID() << ", item " << objectp->getAttachmentItemID() << llendl;
|
||||||
objects_to_remove.push_back(objectp);
|
current_item_ids.insert(object_item_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3415,21 +3415,50 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove)
|
||||||
llwarns << "called with empty list, nothing to do" << llendl;
|
llwarns << "called with empty list, nothing to do" << llendl;
|
||||||
}
|
}
|
||||||
for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it)
|
for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it)
|
||||||
{
|
{
|
||||||
const LLUUID& id_to_remove = *it;
|
const LLUUID& id_to_remove = *it;
|
||||||
const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove);
|
const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove);
|
||||||
removeCOFItemLinks(linked_item_id);
|
removeCOFItemLinks(linked_item_id);
|
||||||
}
|
addDoomedTempAttachment(linked_item_id);
|
||||||
updateAppearanceFromCOF();
|
|
||||||
}
|
}
|
||||||
|
updateAppearanceFromCOF();
|
||||||
|
}
|
||||||
|
|
||||||
void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove)
|
void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove)
|
||||||
{
|
{
|
||||||
LLUUID linked_item_id = gInventory.getLinkedItemID(id_to_remove);
|
LLUUID linked_item_id = gInventory.getLinkedItemID(id_to_remove);
|
||||||
removeCOFItemLinks(linked_item_id);
|
removeCOFItemLinks(linked_item_id);
|
||||||
|
addDoomedTempAttachment(linked_item_id);
|
||||||
updateAppearanceFromCOF();
|
updateAppearanceFromCOF();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Adds the given item ID to mDoomedTempAttachmentIDs iff it's a temp attachment
|
||||||
|
void LLAppearanceMgr::addDoomedTempAttachment(const LLUUID& id_to_remove)
|
||||||
|
{
|
||||||
|
LLViewerObject * attachmentp = gAgentAvatarp->findAttachmentByID(id_to_remove);
|
||||||
|
if (attachmentp &&
|
||||||
|
attachmentp->isTempAttachment())
|
||||||
|
{ // If this is a temp attachment and we want to remove it, record the ID
|
||||||
|
// so it will be deleted when attachments are synced up with COF
|
||||||
|
mDoomedTempAttachmentIDs.insert(id_to_remove);
|
||||||
|
//llinfos << "Will remove temp attachment id " << id_to_remove << llendl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find AND REMOVES the given UUID from mDoomedTempAttachmentIDs
|
||||||
|
bool LLAppearanceMgr::shouldRemoveTempAttachment(const LLUUID& item_id)
|
||||||
|
{
|
||||||
|
doomed_temp_attachments_t::iterator iter = mDoomedTempAttachmentIDs.find(item_id);
|
||||||
|
if (iter != mDoomedTempAttachmentIDs.end())
|
||||||
|
{
|
||||||
|
mDoomedTempAttachmentIDs.erase(iter);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_body)
|
bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_body)
|
||||||
{
|
{
|
||||||
if (!item || !item->isWearableType()) return false;
|
if (!item || !item->isWearableType()) return false;
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,9 @@ public:
|
||||||
void removeAllClothesFromAvatar();
|
void removeAllClothesFromAvatar();
|
||||||
void removeAllAttachmentsFromAvatar();
|
void removeAllAttachmentsFromAvatar();
|
||||||
|
|
||||||
|
// Special handling of temp attachments, which are not in the COF
|
||||||
|
bool shouldRemoveTempAttachment(const LLUUID& item_id);
|
||||||
|
|
||||||
//has the current outfit changed since it was loaded?
|
//has the current outfit changed since it was loaded?
|
||||||
bool isOutfitDirty() { return mOutfitIsDirty; }
|
bool isOutfitDirty() { return mOutfitIsDirty; }
|
||||||
|
|
||||||
|
|
@ -239,6 +242,12 @@ private:
|
||||||
|
|
||||||
std::auto_ptr<LLOutfitUnLockTimer> mUnlockOutfitTimer;
|
std::auto_ptr<LLOutfitUnLockTimer> mUnlockOutfitTimer;
|
||||||
|
|
||||||
|
// Set of temp attachment UUIDs that should be removed
|
||||||
|
typedef std::set<LLUUID> doomed_temp_attachments_t;
|
||||||
|
doomed_temp_attachments_t mDoomedTempAttachmentIDs;
|
||||||
|
|
||||||
|
void addDoomedTempAttachment(const LLUUID& id_to_remove);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
// Item-specific convenience functions
|
// Item-specific convenience functions
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -223,6 +223,10 @@
|
||||||
#include "llmachineid.h"
|
#include "llmachineid.h"
|
||||||
#include "llmainlooprepeater.h"
|
#include "llmainlooprepeater.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "llviewereventrecorder.h"
|
||||||
|
|
||||||
|
|
||||||
// *FIX: These extern globals should be cleaned up.
|
// *FIX: These extern globals should be cleaned up.
|
||||||
// The globals either represent state/config/resource-storage of either
|
// The globals either represent state/config/resource-storage of either
|
||||||
// this app, or another 'component' of the viewer. App globals should be
|
// this app, or another 'component' of the viewer. App globals should be
|
||||||
|
|
@ -696,6 +700,7 @@ LLAppViewer::LLAppViewer() :
|
||||||
LLAppViewer::~LLAppViewer()
|
LLAppViewer::~LLAppViewer()
|
||||||
{
|
{
|
||||||
delete mSettingsLocationList;
|
delete mSettingsLocationList;
|
||||||
|
LLViewerEventRecorder::instance().~LLViewerEventRecorder();
|
||||||
|
|
||||||
LLLoginInstance::instance().setUpdaterService(0);
|
LLLoginInstance::instance().setUpdaterService(0);
|
||||||
|
|
||||||
|
|
@ -2250,13 +2255,13 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key,
|
||||||
|
|
||||||
BOOST_FOREACH(const SettingsFile& file, group.files)
|
BOOST_FOREACH(const SettingsFile& file, group.files)
|
||||||
{
|
{
|
||||||
llinfos << "Attempting to load settings for the group " << file.name()
|
LL_INFOS("Settings") << "Attempting to load settings for the group " << file.name()
|
||||||
<< " - from location " << location_key << llendl;
|
<< " - from location " << location_key << LL_ENDL;
|
||||||
|
|
||||||
LLControlGroup* settings_group = LLControlGroup::getInstance(file.name);
|
LLControlGroup* settings_group = LLControlGroup::getInstance(file.name);
|
||||||
if(!settings_group)
|
if(!settings_group)
|
||||||
{
|
{
|
||||||
llwarns << "No matching settings group for name " << file.name() << llendl;
|
LL_WARNS("Settings") << "No matching settings group for name " << file.name() << LL_ENDL;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2285,7 +2290,7 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key,
|
||||||
|
|
||||||
if(settings_group->loadFromFile(full_settings_path, set_defaults, file.persistent))
|
if(settings_group->loadFromFile(full_settings_path, set_defaults, file.persistent))
|
||||||
{ // success!
|
{ // success!
|
||||||
llinfos << "Loaded settings file " << full_settings_path << llendl;
|
LL_INFOS("Settings") << "Loaded settings file " << full_settings_path << LL_ENDL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // failed to load
|
{ // failed to load
|
||||||
|
|
@ -2299,7 +2304,7 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key,
|
||||||
// only complain if we actually have a filename at this point
|
// only complain if we actually have a filename at this point
|
||||||
if (!full_settings_path.empty())
|
if (!full_settings_path.empty())
|
||||||
{
|
{
|
||||||
llinfos << "Cannot load " << full_settings_path << " - No settings found." << llendl;
|
LL_INFOS("Settings") << "Cannot load " << full_settings_path << " - No settings found." << LL_ENDL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2395,8 +2400,6 @@ bool LLAppViewer::initConfiguration()
|
||||||
gSavedSettings.setString("ClientSettingsFile",
|
gSavedSettings.setString("ClientSettingsFile",
|
||||||
gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Global")));
|
gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Global")));
|
||||||
|
|
||||||
gSavedSettings.setString("VersionChannelName", LLVersionInfo::getChannel());
|
|
||||||
|
|
||||||
#ifndef LL_RELEASE_FOR_DOWNLOAD
|
#ifndef LL_RELEASE_FOR_DOWNLOAD
|
||||||
// provide developer build only overrides for these control variables that are not
|
// provide developer build only overrides for these control variables that are not
|
||||||
// persisted to settings.xml
|
// persisted to settings.xml
|
||||||
|
|
@ -2460,8 +2463,8 @@ bool LLAppViewer::initConfiguration()
|
||||||
gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
|
gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
|
||||||
clp.getOption("settings")[0]);
|
clp.getOption("settings")[0]);
|
||||||
gSavedSettings.setString("ClientSettingsFile", user_settings_filename);
|
gSavedSettings.setString("ClientSettingsFile", user_settings_filename);
|
||||||
llinfos << "Using command line specified settings filename: "
|
LL_INFOS("Settings") << "Using command line specified settings filename: "
|
||||||
<< user_settings_filename << llendl;
|
<< user_settings_filename << LL_ENDL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - load overrides from user_settings
|
// - load overrides from user_settings
|
||||||
|
|
@ -2477,8 +2480,8 @@ bool LLAppViewer::initConfiguration()
|
||||||
{
|
{
|
||||||
std::string session_settings_filename = clp.getOption("sessionsettings")[0];
|
std::string session_settings_filename = clp.getOption("sessionsettings")[0];
|
||||||
gSavedSettings.setString("SessionSettingsFile", session_settings_filename);
|
gSavedSettings.setString("SessionSettingsFile", session_settings_filename);
|
||||||
llinfos << "Using session settings filename: "
|
LL_INFOS("Settings") << "Using session settings filename: "
|
||||||
<< session_settings_filename << llendl;
|
<< session_settings_filename << LL_ENDL;
|
||||||
}
|
}
|
||||||
loadSettingsFromDirectory("Session");
|
loadSettingsFromDirectory("Session");
|
||||||
|
|
||||||
|
|
@ -2486,8 +2489,8 @@ bool LLAppViewer::initConfiguration()
|
||||||
{
|
{
|
||||||
std::string user_session_settings_filename = clp.getOption("usersessionsettings")[0];
|
std::string user_session_settings_filename = clp.getOption("usersessionsettings")[0];
|
||||||
gSavedSettings.setString("UserSessionSettingsFile", user_session_settings_filename);
|
gSavedSettings.setString("UserSessionSettingsFile", user_session_settings_filename);
|
||||||
llinfos << "Using user session settings filename: "
|
LL_INFOS("Settings") << "Using user session settings filename: "
|
||||||
<< user_session_settings_filename << llendl;
|
<< user_session_settings_filename << LL_ENDL;
|
||||||
|
|
||||||
}
|
}
|
||||||
loadSettingsFromDirectory("UserSession");
|
loadSettingsFromDirectory("UserSession");
|
||||||
|
|
@ -2575,9 +2578,13 @@ bool LLAppViewer::initConfiguration()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (clp.hasOption("logevents")) {
|
||||||
|
LLViewerEventRecorder::instance().setEventLoggingOn();
|
||||||
|
}
|
||||||
|
|
||||||
std::string CmdLineChannel(gSavedSettings.getString("CmdLineChannel"));
|
std::string CmdLineChannel(gSavedSettings.getString("CmdLineChannel"));
|
||||||
if(! CmdLineChannel.empty())
|
if(! CmdLineChannel.empty())
|
||||||
{
|
{
|
||||||
LLVersionInfo::resetChannel(CmdLineChannel);
|
LLVersionInfo::resetChannel(CmdLineChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2589,16 +2596,16 @@ bool LLAppViewer::initConfiguration()
|
||||||
LLFastTimer::sLog = TRUE;
|
LLFastTimer::sLog = TRUE;
|
||||||
LLFastTimer::sLogName = std::string("performance");
|
LLFastTimer::sLogName = std::string("performance");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string test_name(gSavedSettings.getString("LogMetrics"));
|
std::string test_name(gSavedSettings.getString("LogMetrics"));
|
||||||
if (! test_name.empty())
|
if (! test_name.empty())
|
||||||
{
|
{
|
||||||
LLFastTimer::sMetricLog = TRUE ;
|
LLFastTimer::sMetricLog = TRUE ;
|
||||||
// '--logmetrics' is specified with a named test metric argument so the data gathering is done only on that test
|
// '--logmetrics' is specified with a named test metric argument so the data gathering is done only on that test
|
||||||
// In the absence of argument, every metric would be gathered (makes for a rather slow run and hard to decipher report...)
|
// In the absence of argument, every metric would be gathered (makes for a rather slow run and hard to decipher report...)
|
||||||
llinfos << "'--logmetrics' argument : " << test_name << llendl;
|
llinfos << "'--logmetrics' argument : " << test_name << llendl;
|
||||||
LLFastTimer::sLogName = test_name;
|
LLFastTimer::sLogName = test_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clp.hasOption("graphicslevel"))
|
if (clp.hasOption("graphicslevel"))
|
||||||
{
|
{
|
||||||
|
|
@ -2607,14 +2614,14 @@ bool LLAppViewer::initConfiguration()
|
||||||
// that value for validity.
|
// that value for validity.
|
||||||
U32 graphicslevel = gSavedSettings.getU32("RenderQualityPerformance");
|
U32 graphicslevel = gSavedSettings.getU32("RenderQualityPerformance");
|
||||||
if (LLFeatureManager::instance().isValidGraphicsLevel(graphicslevel))
|
if (LLFeatureManager::instance().isValidGraphicsLevel(graphicslevel))
|
||||||
{
|
{
|
||||||
// graphicslevel is valid: save it and engage it later. Capture
|
// graphicslevel is valid: save it and engage it later. Capture
|
||||||
// the requested value separately from the settings variable
|
// the requested value separately from the settings variable
|
||||||
// because, if this is the first run, LLViewerWindow's constructor
|
// because, if this is the first run, LLViewerWindow's constructor
|
||||||
// will call LLFeatureManager::applyRecommendedSettings(), which
|
// will call LLFeatureManager::applyRecommendedSettings(), which
|
||||||
// overwrites this settings variable!
|
// overwrites this settings variable!
|
||||||
mForceGraphicsLevel = graphicslevel;
|
mForceGraphicsLevel = graphicslevel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LLFastTimerView::sAnalyzePerformance = gSavedSettings.getBOOL("AnalyzePerformance");
|
LLFastTimerView::sAnalyzePerformance = gSavedSettings.getBOOL("AnalyzePerformance");
|
||||||
|
|
@ -2645,16 +2652,32 @@ bool LLAppViewer::initConfiguration()
|
||||||
// What can happen is that someone can use IE (or potentially
|
// What can happen is that someone can use IE (or potentially
|
||||||
// other browsers) and do the rough equivalent of command
|
// other browsers) and do the rough equivalent of command
|
||||||
// injection and steal passwords. Phoenix. SL-55321
|
// injection and steal passwords. Phoenix. SL-55321
|
||||||
|
LLSLURL start_slurl;
|
||||||
std::string CmdLineLoginLocation(gSavedSettings.getString("CmdLineLoginLocation"));
|
std::string CmdLineLoginLocation(gSavedSettings.getString("CmdLineLoginLocation"));
|
||||||
if(! CmdLineLoginLocation.empty())
|
if(! CmdLineLoginLocation.empty())
|
||||||
{
|
{
|
||||||
LLSLURL start_slurl(CmdLineLoginLocation);
|
start_slurl = CmdLineLoginLocation;
|
||||||
LLStartUp::setStartSLURL(start_slurl);
|
LLStartUp::setStartSLURL(start_slurl);
|
||||||
if(start_slurl.getType() == LLSLURL::LOCATION)
|
if(start_slurl.getType() == LLSLURL::LOCATION)
|
||||||
{
|
{
|
||||||
LLGridManager::getInstance()->setGridChoice(start_slurl.getGrid());
|
LLGridManager::getInstance()->setGridChoice(start_slurl.getGrid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//RN: if we received a URL, hand it off to the existing instance.
|
||||||
|
// don't call anotherInstanceRunning() when doing URL handoff, as
|
||||||
|
// it relies on checking a marker file which will not work when running
|
||||||
|
// out of different directories
|
||||||
|
|
||||||
|
if (start_slurl.isValid() &&
|
||||||
|
(gSavedSettings.getBOOL("SLURLPassToOtherInstance")))
|
||||||
|
{
|
||||||
|
if (sendURLToOtherInstance(start_slurl.getSLURLString()))
|
||||||
|
{
|
||||||
|
// successfully handed off URL to existing instance, exit
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent");
|
const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent");
|
||||||
if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString())
|
if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString())
|
||||||
|
|
@ -2795,7 +2818,7 @@ bool LLAppViewer::initConfiguration()
|
||||||
LL_DEBUGS("AppInit")<<"set start from NextLoginLocation: "<<nextLoginLocation<<LL_ENDL;
|
LL_DEBUGS("AppInit")<<"set start from NextLoginLocation: "<<nextLoginLocation<<LL_ENDL;
|
||||||
LLStartUp::setStartSLURL(LLSLURL(nextLoginLocation));
|
LLStartUp::setStartSLURL(LLSLURL(nextLoginLocation));
|
||||||
}
|
}
|
||||||
else if ((clp.hasOption("login") || clp.hasOption("autologin"))
|
else if ( ( clp.hasOption("login") || clp.hasOption("autologin"))
|
||||||
&& gSavedSettings.getString("CmdLineLoginLocation").empty())
|
&& gSavedSettings.getString("CmdLineLoginLocation").empty())
|
||||||
{
|
{
|
||||||
// If automatic login from command line with --login switch
|
// If automatic login from command line with --login switch
|
||||||
|
|
@ -3179,7 +3202,7 @@ bool LLAppViewer::initWindow()
|
||||||
LLFeatureManager::getInstance()->setGraphicsLevel(*mForceGraphicsLevel, false);
|
LLFeatureManager::getInstance()->setGraphicsLevel(*mForceGraphicsLevel, false);
|
||||||
gSavedSettings.setU32("RenderQualityPerformance", *mForceGraphicsLevel);
|
gSavedSettings.setU32("RenderQualityPerformance", *mForceGraphicsLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set this flag in case we crash while initializing GL
|
// Set this flag in case we crash while initializing GL
|
||||||
gSavedSettings.setBOOL("RenderInitError", TRUE);
|
gSavedSettings.setBOOL("RenderInitError", TRUE);
|
||||||
gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE );
|
gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE );
|
||||||
|
|
|
||||||
|
|
@ -172,21 +172,20 @@ void ll_nvapi_init(NvDRSSessionHandle hSession)
|
||||||
nvapi_error(status);
|
nvapi_error(status);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// (5) Now we apply (or save) our changes to the system
|
||||||
|
status = NvAPI_DRS_SaveSettings(hSession);
|
||||||
|
if (status != NVAPI_OK)
|
||||||
|
{
|
||||||
|
nvapi_error(status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (status != NVAPI_OK)
|
else if (status != NVAPI_OK)
|
||||||
{
|
{
|
||||||
nvapi_error(status);
|
nvapi_error(status);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// (5) Now we apply (or save) our changes to the system
|
|
||||||
status = NvAPI_DRS_SaveSettings(hSession);
|
|
||||||
if (status != NVAPI_OK)
|
|
||||||
{
|
|
||||||
nvapi_error(status);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//#define DEBUGGING_SEH_FILTER 1
|
//#define DEBUGGING_SEH_FILTER 1
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,8 @@
|
||||||
#include "llcallingcard.h"
|
#include "llcallingcard.h"
|
||||||
#include "llslurl.h" // IDEVO
|
#include "llslurl.h" // IDEVO
|
||||||
#include "llsidepanelinventory.h"
|
#include "llsidepanelinventory.h"
|
||||||
|
#include "llavatarname.h"
|
||||||
|
#include "llagentui.h"
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void LLAvatarActions::requestFriendshipDialog(const LLUUID& id, const std::string& name)
|
void LLAvatarActions::requestFriendshipDialog(const LLUUID& id, const std::string& name)
|
||||||
|
|
@ -391,6 +393,72 @@ void LLAvatarActions::pay(const LLUUID& id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LLAvatarActions::teleport_request_callback(const LLSD& notification, const LLSD& response)
|
||||||
|
{
|
||||||
|
S32 option;
|
||||||
|
if (response.isInteger())
|
||||||
|
{
|
||||||
|
option = response.asInteger();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
option = LLNotificationsUtil::getSelectedOption(notification, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == option)
|
||||||
|
{
|
||||||
|
LLMessageSystem* msg = gMessageSystem;
|
||||||
|
|
||||||
|
msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
|
||||||
|
msg->nextBlockFast(_PREHASH_AgentData);
|
||||||
|
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
||||||
|
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
||||||
|
|
||||||
|
msg->nextBlockFast(_PREHASH_MessageBlock);
|
||||||
|
msg->addBOOLFast(_PREHASH_FromGroup, FALSE);
|
||||||
|
msg->addUUIDFast(_PREHASH_ToAgentID, notification["substitutions"]["uuid"] );
|
||||||
|
msg->addU8Fast(_PREHASH_Offline, IM_ONLINE);
|
||||||
|
msg->addU8Fast(_PREHASH_Dialog, IM_TELEPORT_REQUEST);
|
||||||
|
msg->addUUIDFast(_PREHASH_ID, LLUUID::null);
|
||||||
|
msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
LLAgentUI::buildFullname(name);
|
||||||
|
|
||||||
|
msg->addStringFast(_PREHASH_FromAgentName, name);
|
||||||
|
msg->addStringFast(_PREHASH_Message, response["message"]);
|
||||||
|
msg->addU32Fast(_PREHASH_ParentEstateID, 0);
|
||||||
|
msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null);
|
||||||
|
msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
|
||||||
|
|
||||||
|
gMessageSystem->addBinaryDataFast(
|
||||||
|
_PREHASH_BinaryBucket,
|
||||||
|
EMPTY_BINARY_BUCKET,
|
||||||
|
EMPTY_BINARY_BUCKET_SIZE);
|
||||||
|
|
||||||
|
gAgent.sendReliableMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void LLAvatarActions::teleportRequest(const LLUUID& id)
|
||||||
|
{
|
||||||
|
LLSD notification;
|
||||||
|
notification["uuid"] = id;
|
||||||
|
LLAvatarName av_name;
|
||||||
|
if (!LLAvatarNameCache::get(id, &av_name))
|
||||||
|
{
|
||||||
|
// unlikely ... they just picked this name from somewhere...
|
||||||
|
LLAvatarNameCache::get(id, boost::bind(&LLAvatarActions::teleportRequest, id));
|
||||||
|
return; // reinvoke this when the name resolves
|
||||||
|
}
|
||||||
|
notification["NAME"] = av_name.getCompleteName();
|
||||||
|
|
||||||
|
LLSD payload;
|
||||||
|
|
||||||
|
LLNotificationsUtil::add("TeleportRequestPrompt", notification, payload, teleport_request_callback);
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void LLAvatarActions::kick(const LLUUID& id)
|
void LLAvatarActions::kick(const LLUUID& id)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,12 @@ public:
|
||||||
*/
|
*/
|
||||||
static void pay(const LLUUID& id);
|
static void pay(const LLUUID& id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request teleport from other avatar
|
||||||
|
*/
|
||||||
|
static void teleportRequest(const LLUUID& id);
|
||||||
|
static void teleport_request_callback(const LLSD& notification, const LLSD& response);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Share items with the avatar.
|
* Share items with the avatar.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -220,18 +220,25 @@ void LLNotificationChiclet::setCounter(S32 counter)
|
||||||
|
|
||||||
bool LLNotificationChiclet::ChicletNotificationChannel::filterNotification( LLNotificationPtr notification )
|
bool LLNotificationChiclet::ChicletNotificationChannel::filterNotification( LLNotificationPtr notification )
|
||||||
{
|
{
|
||||||
if (notification->getName() == "ScriptDialog")
|
bool displayNotification;
|
||||||
|
if ( (notification->getName() == "ScriptDialog") // special case for scripts
|
||||||
|
// if there is no toast window for the notification, filter it
|
||||||
|
|| (!LLNotificationWellWindow::getInstance()->findItemByID(notification->getID()))
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return false;
|
displayNotification = false;
|
||||||
}
|
}
|
||||||
|
else if( !(notification->canLogToIM() && notification->hasFormElements())
|
||||||
if( !(notification->canLogToIM() && notification->hasFormElements())
|
&& (!notification->getPayload().has("give_inventory_notification")
|
||||||
&& (!notification->getPayload().has("give_inventory_notification")
|
|| notification->getPayload()["give_inventory_notification"]))
|
||||||
|| notification->getPayload()["give_inventory_notification"]))
|
|
||||||
{
|
{
|
||||||
return true;
|
displayNotification = true;
|
||||||
}
|
}
|
||||||
return false;
|
else
|
||||||
|
{
|
||||||
|
displayNotification = false;
|
||||||
|
}
|
||||||
|
return displayNotification;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
||||||
|
|
@ -313,6 +313,10 @@ void LLConversationLogList::onCustomAction(const LLSD& userdata)
|
||||||
{
|
{
|
||||||
LLAvatarActions::offerTeleport(selected_conversation_participant_id);
|
LLAvatarActions::offerTeleport(selected_conversation_participant_id);
|
||||||
}
|
}
|
||||||
|
else if ("request_teleport" == command_name)
|
||||||
|
{
|
||||||
|
LLAvatarActions::teleportRequest(selected_conversation_participant_id);
|
||||||
|
}
|
||||||
else if("add_friend" == command_name)
|
else if("add_friend" == command_name)
|
||||||
{
|
{
|
||||||
if (!LLAvatarActions::isFriend(selected_conversation_participant_id))
|
if (!LLAvatarActions::isFriend(selected_conversation_participant_id))
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,7 @@ void LLConversationItem::buildParticipantMenuOptions(menuentry_vec_t& items, U32
|
||||||
items.push_back(std::string("view_profile"));
|
items.push_back(std::string("view_profile"));
|
||||||
items.push_back(std::string("im"));
|
items.push_back(std::string("im"));
|
||||||
items.push_back(std::string("offer_teleport"));
|
items.push_back(std::string("offer_teleport"));
|
||||||
|
items.push_back(std::string("request_teleport"));
|
||||||
items.push_back(std::string("voice_call"));
|
items.push_back(std::string("voice_call"));
|
||||||
items.push_back(std::string("chat_history"));
|
items.push_back(std::string("chat_history"));
|
||||||
items.push_back(std::string("separator_chat_history"));
|
items.push_back(std::string("separator_chat_history"));
|
||||||
|
|
|
||||||
|
|
@ -267,6 +267,23 @@ BOOL LLConversationViewSession::handleMouseDown( S32 x, S32 y, MASK mask )
|
||||||
//This node (conversation) was selected and a child (participant) was not
|
//This node (conversation) was selected and a child (participant) was not
|
||||||
if(result && getRoot())
|
if(result && getRoot())
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if(getRoot()->getCurSelectedItem() == this)
|
||||||
|
{
|
||||||
|
LLConversationItem* item = dynamic_cast<LLConversationItem *>(getViewModelItem());
|
||||||
|
LLUUID session_id = item? item->getUUID() : LLUUID();
|
||||||
|
|
||||||
|
LLFloaterIMContainer *im_container = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
|
||||||
|
if (im_container->isConversationsPaneCollapsed() && im_container->getSelectedSession() == session_id)
|
||||||
|
{
|
||||||
|
im_container->collapseMessagesPane(!im_container->isMessagesPaneCollapsed());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
im_container->collapseMessagesPane(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
selectConversationItem();
|
selectConversationItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -316,14 +333,6 @@ void LLConversationViewSession::selectConversationItem()
|
||||||
LLUUID session_id = item? item->getUUID() : LLUUID();
|
LLUUID session_id = item? item->getUUID() : LLUUID();
|
||||||
|
|
||||||
LLFloaterIMContainer *im_container = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
|
LLFloaterIMContainer *im_container = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
|
||||||
if (im_container->isConversationsPaneCollapsed() && im_container->getSelectedSession() == session_id)
|
|
||||||
{
|
|
||||||
im_container->collapseMessagesPane(!im_container->isMessagesPaneCollapsed());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
im_container->collapseMessagesPane(false);
|
|
||||||
}
|
|
||||||
im_container->flashConversationItemWidget(session_id,false);
|
im_container->flashConversationItemWidget(session_id,false);
|
||||||
im_container->selectConversationPair(session_id, false);
|
im_container->selectConversationPair(session_id, false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -382,9 +382,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
|
||||||
bool is_particle_or_hud_particle = group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_PARTICLE
|
bool is_particle_or_hud_particle = group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_PARTICLE
|
||||||
|| group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD_PARTICLE;
|
|| group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD_PARTICLE;
|
||||||
|
|
||||||
bool draw_glow_for_this_partition = mVertexShaderLevel > 0 && // no shaders = no glow.
|
bool draw_glow_for_this_partition = mVertexShaderLevel > 0; // no shaders = no glow.
|
||||||
// All particle systems seem to come off the wire with texture entries which claim that they glow. This is probably a bug in the data. Suppress.
|
|
||||||
!is_particle_or_hud_particle;
|
|
||||||
|
|
||||||
static LLFastTimer::DeclareTimer FTM_RENDER_ALPHA_GROUP_LOOP("Alpha Group");
|
static LLFastTimer::DeclareTimer FTM_RENDER_ALPHA_GROUP_LOOP("Alpha Group");
|
||||||
LLFastTimer t(FTM_RENDER_ALPHA_GROUP_LOOP);
|
LLFastTimer t(FTM_RENDER_ALPHA_GROUP_LOOP);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,582 @@
|
||||||
|
/**
|
||||||
|
* @file llfacebookconnect.h
|
||||||
|
* @author Merov, Cho, Gil
|
||||||
|
* @brief Connection to Facebook Service
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
|
||||||
|
* Second Life Viewer Source Code
|
||||||
|
* Copyright (C) 2013, Linden Research, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation;
|
||||||
|
* version 2.1 of the License only.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
|
* $/LicenseInfo$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "llviewerprecompiledheaders.h"
|
||||||
|
|
||||||
|
#include "llfacebookconnect.h"
|
||||||
|
|
||||||
|
#include "llagent.h"
|
||||||
|
#include "llcallingcard.h" // for LLAvatarTracker
|
||||||
|
#include "llcommandhandler.h"
|
||||||
|
#include "llhttpclient.h"
|
||||||
|
#include "llnotificationsutil.h"
|
||||||
|
#include "llurlaction.h"
|
||||||
|
#include "llimagepng.h"
|
||||||
|
#include "llimagejpeg.h"
|
||||||
|
#include "lltrans.h"
|
||||||
|
#include "llevents.h"
|
||||||
|
#include "llviewerregion.h"
|
||||||
|
|
||||||
|
#include "llfloaterwebcontent.h"
|
||||||
|
#include "llfloaterreg.h"
|
||||||
|
|
||||||
|
boost::scoped_ptr<LLEventPump> LLFacebookConnect::sStateWatcher(new LLEventStream("FacebookConnectState"));
|
||||||
|
boost::scoped_ptr<LLEventPump> LLFacebookConnect::sInfoWatcher(new LLEventStream("FacebookConnectInfo"));
|
||||||
|
boost::scoped_ptr<LLEventPump> LLFacebookConnect::sContentWatcher(new LLEventStream("FacebookConnectContent"));
|
||||||
|
|
||||||
|
// Local functions
|
||||||
|
void log_facebook_connect_error(const std::string& request, U32 status, const std::string& reason, const std::string& code, const std::string& description)
|
||||||
|
{
|
||||||
|
// Note: 302 (redirect) is *not* an error that warrants logging
|
||||||
|
if (status != 302)
|
||||||
|
{
|
||||||
|
LL_WARNS("FacebookConnect") << request << " request failed with a " << status << " " << reason << ". Reason: " << code << " (" << description << ")" << LL_ENDL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void toast_user_for_success()
|
||||||
|
{
|
||||||
|
LLSD args;
|
||||||
|
args["MESSAGE"] = LLTrans::getString("facebook_post_success");
|
||||||
|
LLNotificationsUtil::add("FacebookConnect", args);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
class LLFacebookConnectHandler : public LLCommandHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LLFacebookConnectHandler() : LLCommandHandler("fbc", UNTRUSTED_THROTTLE) { }
|
||||||
|
|
||||||
|
bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web)
|
||||||
|
{
|
||||||
|
if (tokens.size() > 0)
|
||||||
|
{
|
||||||
|
if (tokens[0].asString() == "connect")
|
||||||
|
{
|
||||||
|
// this command probably came from the fbc_web browser, so close it
|
||||||
|
LLFloater* fbc_web = LLFloaterReg::getInstance("fbc_web");
|
||||||
|
if (fbc_web)
|
||||||
|
{
|
||||||
|
fbc_web->closeFloater();
|
||||||
|
}
|
||||||
|
|
||||||
|
// connect to facebook
|
||||||
|
if (query_map.has("code"))
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().connectToFacebook(query_map["code"], query_map.get("state"));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
LLFacebookConnectHandler gFacebookConnectHandler;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
class LLFacebookConnectResponder : public LLHTTPClient::Responder
|
||||||
|
{
|
||||||
|
LOG_CLASS(LLFacebookConnectResponder);
|
||||||
|
public:
|
||||||
|
|
||||||
|
LLFacebookConnectResponder()
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void completed(U32 status, const std::string& reason, const LLSD& content)
|
||||||
|
{
|
||||||
|
if (isGoodStatus(status))
|
||||||
|
{
|
||||||
|
LL_DEBUGS("FacebookConnect") << "Connect successful. content: " << content << LL_ENDL;
|
||||||
|
|
||||||
|
LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED);
|
||||||
|
}
|
||||||
|
else if (status != 302)
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED);
|
||||||
|
log_facebook_connect_error("Connect", status, reason, content.get("error_code"), content.get("error_description"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void completedHeader(U32 status, const std::string& reason, const LLSD& content)
|
||||||
|
{
|
||||||
|
if (status == 302)
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().openFacebookWeb(content["location"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
class LLFacebookShareResponder : public LLHTTPClient::Responder
|
||||||
|
{
|
||||||
|
LOG_CLASS(LLFacebookShareResponder);
|
||||||
|
public:
|
||||||
|
|
||||||
|
LLFacebookShareResponder()
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTING);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void completed(U32 status, const std::string& reason, const LLSD& content)
|
||||||
|
{
|
||||||
|
if (isGoodStatus(status))
|
||||||
|
{
|
||||||
|
toast_user_for_success();
|
||||||
|
LL_DEBUGS("FacebookConnect") << "Post successful. content: " << content << LL_ENDL;
|
||||||
|
|
||||||
|
LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTED);
|
||||||
|
}
|
||||||
|
else if (status == 404)
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().connectToFacebook();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POST_FAILED);
|
||||||
|
log_facebook_connect_error("Share", status, reason, content.get("error_code"), content.get("error_description"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void completedHeader(U32 status, const std::string& reason, const LLSD& content)
|
||||||
|
{
|
||||||
|
if (status == 302)
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().openFacebookWeb(content["location"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
class LLFacebookDisconnectResponder : public LLHTTPClient::Responder
|
||||||
|
{
|
||||||
|
LOG_CLASS(LLFacebookDisconnectResponder);
|
||||||
|
public:
|
||||||
|
|
||||||
|
LLFacebookDisconnectResponder()
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECTING);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUserDisconnected()
|
||||||
|
{
|
||||||
|
// Clear data
|
||||||
|
LLFacebookConnect::instance().clearInfo();
|
||||||
|
LLFacebookConnect::instance().clearContent();
|
||||||
|
//Notify state change
|
||||||
|
LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void completed(U32 status, const std::string& reason, const LLSD& content)
|
||||||
|
{
|
||||||
|
if (isGoodStatus(status))
|
||||||
|
{
|
||||||
|
LL_DEBUGS("FacebookConnect") << "Disconnect successful. content: " << content << LL_ENDL;
|
||||||
|
setUserDisconnected();
|
||||||
|
|
||||||
|
}
|
||||||
|
//User not found so already disconnected
|
||||||
|
else if(status == 404)
|
||||||
|
{
|
||||||
|
LL_DEBUGS("FacebookConnect") << "Already disconnected. content: " << content << LL_ENDL;
|
||||||
|
setUserDisconnected();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED);
|
||||||
|
log_facebook_connect_error("Disconnect", status, reason, content.get("error_code"), content.get("error_description"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
class LLFacebookConnectedResponder : public LLHTTPClient::Responder
|
||||||
|
{
|
||||||
|
LOG_CLASS(LLFacebookConnectedResponder);
|
||||||
|
public:
|
||||||
|
|
||||||
|
LLFacebookConnectedResponder(bool auto_connect) : mAutoConnect(auto_connect)
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void completed(U32 status, const std::string& reason, const LLSD& content)
|
||||||
|
{
|
||||||
|
if (isGoodStatus(status))
|
||||||
|
{
|
||||||
|
LL_DEBUGS("FacebookConnect") << "Connect successful. content: " << content << LL_ENDL;
|
||||||
|
|
||||||
|
LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// show the facebook login page if not connected yet
|
||||||
|
if (status == 404)
|
||||||
|
{
|
||||||
|
if (mAutoConnect)
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().connectToFacebook();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED);
|
||||||
|
log_facebook_connect_error("Connected", status, reason, content.get("error_code"), content.get("error_description"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool mAutoConnect;
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
class LLFacebookInfoResponder : public LLHTTPClient::Responder
|
||||||
|
{
|
||||||
|
LOG_CLASS(LLFacebookInfoResponder);
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void completed(U32 status, const std::string& reason, const LLSD& info)
|
||||||
|
{
|
||||||
|
if (isGoodStatus(status))
|
||||||
|
{
|
||||||
|
llinfos << "Facebook: Info received" << llendl;
|
||||||
|
LL_DEBUGS("FacebookConnect") << "Getting Facebook info successful. info: " << info << LL_ENDL;
|
||||||
|
LLFacebookConnect::instance().storeInfo(info);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_facebook_connect_error("Info", status, reason, info.get("error_code"), info.get("error_description"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void completedHeader(U32 status, const std::string& reason, const LLSD& content)
|
||||||
|
{
|
||||||
|
if (status == 302)
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().openFacebookWeb(content["location"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
class LLFacebookFriendsResponder : public LLHTTPClient::Responder
|
||||||
|
{
|
||||||
|
LOG_CLASS(LLFacebookFriendsResponder);
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void completed(U32 status, const std::string& reason, const LLSD& content)
|
||||||
|
{
|
||||||
|
if (isGoodStatus(status))
|
||||||
|
{
|
||||||
|
LL_DEBUGS("FacebookConnect") << "Getting Facebook friends successful. content: " << content << LL_ENDL;
|
||||||
|
LLFacebookConnect::instance().storeContent(content);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_facebook_connect_error("Friends", status, reason, content.get("error_code"), content.get("error_description"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void completedHeader(U32 status, const std::string& reason, const LLSD& content)
|
||||||
|
{
|
||||||
|
if (status == 302)
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().openFacebookWeb(content["location"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
LLFacebookConnect::LLFacebookConnect()
|
||||||
|
: mConnectionState(FB_NOT_CONNECTED),
|
||||||
|
mConnected(false),
|
||||||
|
mInfo(),
|
||||||
|
mContent(),
|
||||||
|
mRefreshInfo(false),
|
||||||
|
mRefreshContent(false),
|
||||||
|
mReadFromMaster(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFacebookConnect::openFacebookWeb(std::string url)
|
||||||
|
{
|
||||||
|
// Open the URL in an internal browser window without navigation UI
|
||||||
|
LLFloaterWebContent::Params p;
|
||||||
|
p.url(url).show_chrome(true);
|
||||||
|
p.url(url).allow_address_entry(false);
|
||||||
|
p.url(url).allow_back_forward_navigation(false);
|
||||||
|
p.url(url).trusted_content(true);
|
||||||
|
LLFloater *floater = LLFloaterReg::showInstance("fbc_web", p);
|
||||||
|
//the internal web browser has a bug that prevents it from gaining focus unless a mouse event occurs first (it seems).
|
||||||
|
//So when showing the internal web browser, set focus to it's containing floater "fbc_web". When a mouse event
|
||||||
|
//occurs on the "webbrowser" panel part of the floater, a mouse cursor will properly show and the "webbrowser" will gain focus.
|
||||||
|
//fbc_web floater contains the "webbrowser" panel. JIRA: ACME-744
|
||||||
|
gFocusMgr.setKeyboardFocus( floater );
|
||||||
|
|
||||||
|
//LLUrlAction::openURLExternal(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string LLFacebookConnect::getFacebookConnectURL(const std::string& route, bool include_read_from_master)
|
||||||
|
{
|
||||||
|
std::string url("");
|
||||||
|
LLViewerRegion *regionp = gAgent.getRegion();
|
||||||
|
if (regionp)
|
||||||
|
{
|
||||||
|
url = regionp->getCapability("FacebookConnect");
|
||||||
|
url += route;
|
||||||
|
|
||||||
|
if (include_read_from_master && mReadFromMaster)
|
||||||
|
{
|
||||||
|
url += "?read_from_master=true";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFacebookConnect::connectToFacebook(const std::string& auth_code, const std::string& auth_state)
|
||||||
|
{
|
||||||
|
LLSD body;
|
||||||
|
if (!auth_code.empty())
|
||||||
|
body["code"] = auth_code;
|
||||||
|
if (!auth_state.empty())
|
||||||
|
body["state"] = auth_state;
|
||||||
|
|
||||||
|
LLHTTPClient::put(getFacebookConnectURL("/connection"), body, new LLFacebookConnectResponder());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFacebookConnect::disconnectFromFacebook()
|
||||||
|
{
|
||||||
|
LLHTTPClient::del(getFacebookConnectURL("/connection"), new LLFacebookDisconnectResponder());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFacebookConnect::checkConnectionToFacebook(bool auto_connect)
|
||||||
|
{
|
||||||
|
const bool follow_redirects = false;
|
||||||
|
const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
|
||||||
|
LLHTTPClient::get(getFacebookConnectURL("/connection", true), new LLFacebookConnectedResponder(auto_connect),
|
||||||
|
LLSD(), timeout, follow_redirects);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFacebookConnect::loadFacebookInfo()
|
||||||
|
{
|
||||||
|
if(mRefreshInfo)
|
||||||
|
{
|
||||||
|
const bool follow_redirects = false;
|
||||||
|
const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
|
||||||
|
LLHTTPClient::get(getFacebookConnectURL("/info", true), new LLFacebookInfoResponder(),
|
||||||
|
LLSD(), timeout, follow_redirects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFacebookConnect::loadFacebookFriends()
|
||||||
|
{
|
||||||
|
if(mRefreshContent)
|
||||||
|
{
|
||||||
|
const bool follow_redirects = false;
|
||||||
|
const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
|
||||||
|
LLHTTPClient::get(getFacebookConnectURL("/friends", true), new LLFacebookFriendsResponder(),
|
||||||
|
LLSD(), timeout, follow_redirects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFacebookConnect::postCheckin(const std::string& location, const std::string& name, const std::string& description, const std::string& image, const std::string& message)
|
||||||
|
{
|
||||||
|
LLSD body;
|
||||||
|
if (!location.empty())
|
||||||
|
body["location"] = location;
|
||||||
|
if (!name.empty())
|
||||||
|
body["name"] = name;
|
||||||
|
if (!description.empty())
|
||||||
|
body["description"] = description;
|
||||||
|
if (!image.empty())
|
||||||
|
body["image"] = image;
|
||||||
|
if (!message.empty())
|
||||||
|
body["message"] = message;
|
||||||
|
|
||||||
|
// Note: we can use that route for different publish action. We should be able to use the same responder.
|
||||||
|
LLHTTPClient::post(getFacebookConnectURL("/share/checkin", true), body, new LLFacebookShareResponder());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFacebookConnect::sharePhoto(const std::string& image_url, const std::string& caption)
|
||||||
|
{
|
||||||
|
LLSD body;
|
||||||
|
body["image"] = image_url;
|
||||||
|
body["caption"] = caption;
|
||||||
|
|
||||||
|
// Note: we can use that route for different publish action. We should be able to use the same responder.
|
||||||
|
LLHTTPClient::post(getFacebookConnectURL("/share/photo", true), body, new LLFacebookShareResponder());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFacebookConnect::sharePhoto(LLPointer<LLImageFormatted> image, const std::string& caption)
|
||||||
|
{
|
||||||
|
std::string imageFormat;
|
||||||
|
if (dynamic_cast<LLImagePNG*>(image.get()))
|
||||||
|
{
|
||||||
|
imageFormat = "png";
|
||||||
|
}
|
||||||
|
else if (dynamic_cast<LLImageJPEG*>(image.get()))
|
||||||
|
{
|
||||||
|
imageFormat = "jpg";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
llwarns << "Image to upload is not a PNG or JPEG" << llendl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All this code is mostly copied from LLWebProfile::post()
|
||||||
|
const std::string boundary = "----------------------------0123abcdefab";
|
||||||
|
|
||||||
|
LLSD headers;
|
||||||
|
headers["Content-Type"] = "multipart/form-data; boundary=" + boundary;
|
||||||
|
|
||||||
|
std::ostringstream body;
|
||||||
|
|
||||||
|
// *NOTE: The order seems to matter.
|
||||||
|
body << "--" << boundary << "\r\n"
|
||||||
|
<< "Content-Disposition: form-data; name=\"caption\"\r\n\r\n"
|
||||||
|
<< caption << "\r\n";
|
||||||
|
|
||||||
|
body << "--" << boundary << "\r\n"
|
||||||
|
<< "Content-Disposition: form-data; name=\"image\"; filename=\"snapshot." << imageFormat << "\"\r\n"
|
||||||
|
<< "Content-Type: image/" << imageFormat << "\r\n\r\n";
|
||||||
|
|
||||||
|
// Insert the image data.
|
||||||
|
// *FIX: Treating this as a string will probably screw it up ...
|
||||||
|
U8* image_data = image->getData();
|
||||||
|
for (S32 i = 0; i < image->getDataSize(); ++i)
|
||||||
|
{
|
||||||
|
body << image_data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
body << "\r\n--" << boundary << "--\r\n";
|
||||||
|
|
||||||
|
// postRaw() takes ownership of the buffer and releases it later.
|
||||||
|
size_t size = body.str().size();
|
||||||
|
U8 *data = new U8[size];
|
||||||
|
memcpy(data, body.str().data(), size);
|
||||||
|
|
||||||
|
// Note: we can use that route for different publish action. We should be able to use the same responder.
|
||||||
|
LLHTTPClient::postRaw(getFacebookConnectURL("/share/photo", true), data, size, new LLFacebookShareResponder(), headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFacebookConnect::updateStatus(const std::string& message)
|
||||||
|
{
|
||||||
|
LLSD body;
|
||||||
|
body["message"] = message;
|
||||||
|
|
||||||
|
// Note: we can use that route for different publish action. We should be able to use the same responder.
|
||||||
|
LLHTTPClient::post(getFacebookConnectURL("/share/wall", true), body, new LLFacebookShareResponder());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFacebookConnect::storeInfo(const LLSD& info)
|
||||||
|
{
|
||||||
|
mInfo = info;
|
||||||
|
mRefreshInfo = false;
|
||||||
|
|
||||||
|
sInfoWatcher->post(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
const LLSD& LLFacebookConnect::getInfo() const
|
||||||
|
{
|
||||||
|
return mInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFacebookConnect::clearInfo()
|
||||||
|
{
|
||||||
|
mInfo = LLSD();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFacebookConnect::storeContent(const LLSD& content)
|
||||||
|
{
|
||||||
|
mContent = content;
|
||||||
|
mRefreshContent = false;
|
||||||
|
|
||||||
|
sContentWatcher->post(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
const LLSD& LLFacebookConnect::getContent() const
|
||||||
|
{
|
||||||
|
return mContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFacebookConnect::clearContent()
|
||||||
|
{
|
||||||
|
mContent = LLSD();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFacebookConnect::setDataDirty()
|
||||||
|
{
|
||||||
|
mRefreshInfo = true;
|
||||||
|
mRefreshContent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFacebookConnect::setConnectionState(LLFacebookConnect::EConnectionState connection_state)
|
||||||
|
{
|
||||||
|
if(connection_state == FB_CONNECTED)
|
||||||
|
{
|
||||||
|
mReadFromMaster = true;
|
||||||
|
setConnected(true);
|
||||||
|
setDataDirty();
|
||||||
|
}
|
||||||
|
else if(connection_state == FB_NOT_CONNECTED)
|
||||||
|
{
|
||||||
|
setConnected(false);
|
||||||
|
}
|
||||||
|
else if(connection_state == FB_POSTED)
|
||||||
|
{
|
||||||
|
mReadFromMaster = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mConnectionState != connection_state)
|
||||||
|
{
|
||||||
|
LLSD state_info;
|
||||||
|
state_info["enum"] = connection_state;
|
||||||
|
sStateWatcher->post(state_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
mConnectionState = connection_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFacebookConnect::setConnected(bool connected)
|
||||||
|
{
|
||||||
|
mConnected = connected;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
/**
|
||||||
|
* @file llfacebookconnect.h
|
||||||
|
* @author Merov, Cho, Gil
|
||||||
|
* @brief Connection to Facebook Service
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
|
||||||
|
* Second Life Viewer Source Code
|
||||||
|
* Copyright (C) 2013, Linden Research, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation;
|
||||||
|
* version 2.1 of the License only.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
|
* $/LicenseInfo$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LL_LLFACEBOOKCONNECT_H
|
||||||
|
#define LL_LLFACEBOOKCONNECT_H
|
||||||
|
|
||||||
|
#include "llsingleton.h"
|
||||||
|
#include "llimage.h"
|
||||||
|
|
||||||
|
class LLEventPump;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class LLFacebookConnect
|
||||||
|
*
|
||||||
|
* Manages authentication to, and interaction with, a web service allowing the
|
||||||
|
* the viewer to get Facebook OpenGraph data.
|
||||||
|
*/
|
||||||
|
class LLFacebookConnect : public LLSingleton<LLFacebookConnect>
|
||||||
|
{
|
||||||
|
LOG_CLASS(LLFacebookConnect);
|
||||||
|
public:
|
||||||
|
enum EConnectionState
|
||||||
|
{
|
||||||
|
FB_NOT_CONNECTED = 0,
|
||||||
|
FB_CONNECTION_IN_PROGRESS = 1,
|
||||||
|
FB_CONNECTED = 2,
|
||||||
|
FB_CONNECTION_FAILED = 3,
|
||||||
|
FB_POSTING = 4,
|
||||||
|
FB_POSTED = 5,
|
||||||
|
FB_POST_FAILED = 6,
|
||||||
|
FB_DISCONNECTING = 7,
|
||||||
|
FB_DISCONNECT_FAILED = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
void connectToFacebook(const std::string& auth_code = "", const std::string& auth_state = ""); // Initiate the complete FB connection. Please use checkConnectionToFacebook() in normal use.
|
||||||
|
void disconnectFromFacebook(); // Disconnect from the FBC service.
|
||||||
|
void checkConnectionToFacebook(bool auto_connect = false); // Check if an access token is available on the FBC service. If not, call connectToFacebook().
|
||||||
|
|
||||||
|
void loadFacebookInfo();
|
||||||
|
void loadFacebookFriends();
|
||||||
|
void postCheckin(const std::string& location, const std::string& name, const std::string& description, const std::string& picture, const std::string& message);
|
||||||
|
void sharePhoto(const std::string& image_url, const std::string& caption);
|
||||||
|
void sharePhoto(LLPointer<LLImageFormatted> image, const std::string& caption);
|
||||||
|
void updateStatus(const std::string& message);
|
||||||
|
|
||||||
|
void storeInfo(const LLSD& info);
|
||||||
|
const LLSD& getInfo() const;
|
||||||
|
void clearInfo();
|
||||||
|
void storeContent(const LLSD& content);
|
||||||
|
const LLSD& getContent() const;
|
||||||
|
void clearContent();
|
||||||
|
void setDataDirty();
|
||||||
|
|
||||||
|
void setConnectionState(EConnectionState connection_state);
|
||||||
|
void setConnected(bool connected);
|
||||||
|
bool isConnected() { return mConnected; }
|
||||||
|
bool isTransactionOngoing() { return ((mConnectionState == FB_CONNECTION_IN_PROGRESS) || (mConnectionState == FB_POSTING) || (mConnectionState == FB_DISCONNECTING)); }
|
||||||
|
EConnectionState getConnectionState() { return mConnectionState; }
|
||||||
|
|
||||||
|
void openFacebookWeb(std::string url);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class LLSingleton<LLFacebookConnect>;
|
||||||
|
|
||||||
|
LLFacebookConnect();
|
||||||
|
~LLFacebookConnect() {};
|
||||||
|
std::string getFacebookConnectURL(const std::string& route = "", bool include_read_from_master = false);
|
||||||
|
|
||||||
|
EConnectionState mConnectionState;
|
||||||
|
BOOL mConnected;
|
||||||
|
LLSD mInfo;
|
||||||
|
LLSD mContent;
|
||||||
|
bool mRefreshInfo;
|
||||||
|
bool mRefreshContent;
|
||||||
|
bool mReadFromMaster;
|
||||||
|
|
||||||
|
static boost::scoped_ptr<LLEventPump> sStateWatcher;
|
||||||
|
static boost::scoped_ptr<LLEventPump> sInfoWatcher;
|
||||||
|
static boost::scoped_ptr<LLEventPump> sContentWatcher;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LL_LLFACEBOOKCONNECT_H
|
||||||
|
|
@ -668,10 +668,10 @@ void LLFloaterIMContainer::setVisible(BOOL visible)
|
||||||
LLFloater* session_floater = widget->getSessionFloater();
|
LLFloater* session_floater = widget->getSessionFloater();
|
||||||
if (session_floater != nearby_chat)
|
if (session_floater != nearby_chat)
|
||||||
{
|
{
|
||||||
widget->setVisibleIfDetached(visible);
|
widget->setVisibleIfDetached(visible);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Now, do the normal multifloater show/hide
|
// Now, do the normal multifloater show/hide
|
||||||
LLMultiFloater::setVisible(visible);
|
LLMultiFloater::setVisible(visible);
|
||||||
|
|
@ -706,13 +706,13 @@ void LLFloaterIMContainer::setVisibleAndFrontmost(BOOL take_focus, const LLSD& k
|
||||||
// Only select other sessions
|
// Only select other sessions
|
||||||
if (!getSelectedSession().isNull())
|
if (!getSelectedSession().isNull())
|
||||||
{
|
{
|
||||||
selectConversationPair(getSelectedSession(), false, take_focus);
|
selectConversationPair(getSelectedSession(), false, take_focus);
|
||||||
}
|
}
|
||||||
if (mInitialized && mIsFirstLaunch)
|
if (mInitialized && mIsFirstLaunch)
|
||||||
{
|
{
|
||||||
collapseMessagesPane(gSavedPerAccountSettings.getBOOL("ConversationsMessagePaneCollapsed"));
|
collapseMessagesPane(gSavedPerAccountSettings.getBOOL("ConversationsMessagePaneCollapsed"));
|
||||||
mIsFirstLaunch = false;
|
mIsFirstLaunch = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLFloaterIMContainer::updateResizeLimits()
|
void LLFloaterIMContainer::updateResizeLimits()
|
||||||
|
|
@ -850,7 +850,7 @@ void LLFloaterIMContainer::assignResizeLimits()
|
||||||
|
|
||||||
S32 conv_pane_target_width = is_conv_pane_expanded
|
S32 conv_pane_target_width = is_conv_pane_expanded
|
||||||
? ( is_msg_pane_expanded?mConversationsPane->getRect().getWidth():mConversationsPane->getExpandedMinDim() )
|
? ( is_msg_pane_expanded?mConversationsPane->getRect().getWidth():mConversationsPane->getExpandedMinDim() )
|
||||||
: mConversationsPane->getMinDim();
|
: mConversationsPane->getMinDim();
|
||||||
|
|
||||||
S32 msg_pane_min_width = is_msg_pane_expanded ? mMessagesPane->getExpandedMinDim() : 0;
|
S32 msg_pane_min_width = is_msg_pane_expanded ? mMessagesPane->getExpandedMinDim() : 0;
|
||||||
S32 new_min_width = conv_pane_target_width + msg_pane_min_width + summary_width_of_visible_borders;
|
S32 new_min_width = conv_pane_target_width + msg_pane_min_width + summary_width_of_visible_borders;
|
||||||
|
|
@ -1011,7 +1011,7 @@ void LLFloaterIMContainer::setSortOrder(const LLConversationSort& order)
|
||||||
conversation_floater->setSortOrder(order);
|
conversation_floater->setSortOrder(order);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gSavedSettings.setU32("ConversationSortOrder", (U32)order);
|
gSavedSettings.setU32("ConversationSortOrder", (U32)order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1096,6 +1096,10 @@ void LLFloaterIMContainer::doToParticipants(const std::string& command, uuid_vec
|
||||||
{
|
{
|
||||||
LLAvatarActions::offerTeleport(selectedIDS);
|
LLAvatarActions::offerTeleport(selectedIDS);
|
||||||
}
|
}
|
||||||
|
else if ("request_teleport" == command)
|
||||||
|
{
|
||||||
|
LLAvatarActions::teleportRequest(selectedIDS.front());
|
||||||
|
}
|
||||||
else if ("voice_call" == command)
|
else if ("voice_call" == command)
|
||||||
{
|
{
|
||||||
LLAvatarActions::startCall(userID);
|
LLAvatarActions::startCall(userID);
|
||||||
|
|
@ -1198,7 +1202,7 @@ void LLFloaterIMContainer::doToSelectedConversation(const std::string& command,
|
||||||
}
|
}
|
||||||
else if("chat_history" == command)
|
else if("chat_history" == command)
|
||||||
{
|
{
|
||||||
if (selectedIDS.size() > 0)
|
if (selectedIDS.size() > 0)
|
||||||
{
|
{
|
||||||
LLAvatarActions::viewChatHistory(selectedIDS.front());
|
LLAvatarActions::viewChatHistory(selectedIDS.front());
|
||||||
}
|
}
|
||||||
|
|
@ -1220,7 +1224,7 @@ void LLFloaterIMContainer::doToSelectedConversation(const std::string& command,
|
||||||
{
|
{
|
||||||
LLFloaterReg::showInstance("preview_conversation", LLSD(LLUUID::null), true);
|
LLFloaterReg::showInstance("preview_conversation", LLSD(LLUUID::null), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1251,7 +1255,7 @@ void LLFloaterIMContainer::doToSelectedGroup(const LLSD& userdata)
|
||||||
|
|
||||||
if (action == "group_profile")
|
if (action == "group_profile")
|
||||||
{
|
{
|
||||||
LLGroupActions::show(mSelectedSession);
|
LLGroupActions::show(mSelectedSession);
|
||||||
}
|
}
|
||||||
else if (action == "activate_group")
|
else if (action == "activate_group")
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2097,7 +2097,6 @@ void LLPanelLandOptions::refresh()
|
||||||
// virtual
|
// virtual
|
||||||
void LLPanelLandOptions::draw()
|
void LLPanelLandOptions::draw()
|
||||||
{
|
{
|
||||||
refreshSearch(); // Is this necessary? JC
|
|
||||||
LLPanel::draw();
|
LLPanel::draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2111,9 +2110,8 @@ void LLPanelLandOptions::refreshSearch()
|
||||||
mCheckShowDirectory->set(FALSE);
|
mCheckShowDirectory->set(FALSE);
|
||||||
mCheckShowDirectory->setEnabled(FALSE);
|
mCheckShowDirectory->setEnabled(FALSE);
|
||||||
|
|
||||||
// *TODO:Translate
|
const std::string& none_string = LLParcel::getCategoryString(LLParcel::C_NONE);
|
||||||
const std::string& none_string = LLParcel::getCategoryUIString(LLParcel::C_NONE);
|
mCategoryCombo->setValue(none_string);
|
||||||
mCategoryCombo->setSimple(none_string);
|
|
||||||
mCategoryCombo->setEnabled(FALSE);
|
mCategoryCombo->setEnabled(FALSE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -2140,10 +2138,9 @@ void LLPanelLandOptions::refreshSearch()
|
||||||
mCheckShowDirectory ->set(show_directory);
|
mCheckShowDirectory ->set(show_directory);
|
||||||
|
|
||||||
// Set by string in case the order in UI doesn't match the order by index.
|
// Set by string in case the order in UI doesn't match the order by index.
|
||||||
// *TODO:Translate
|
|
||||||
LLParcel::ECategory cat = parcel->getCategory();
|
LLParcel::ECategory cat = parcel->getCategory();
|
||||||
const std::string& category_string = LLParcel::getCategoryUIString(cat);
|
const std::string& category_string = LLParcel::getCategoryString(cat);
|
||||||
mCategoryCombo->setSimple(category_string);
|
mCategoryCombo->setValue(category_string);
|
||||||
|
|
||||||
std::string tooltip;
|
std::string tooltip;
|
||||||
bool enable_show_directory = false;
|
bool enable_show_directory = false;
|
||||||
|
|
|
||||||
|
|
@ -618,9 +618,12 @@ void LLFloaterPreference::cancel()
|
||||||
// hide translation settings floater
|
// hide translation settings floater
|
||||||
LLFloaterReg::hideInstance("prefs_translation");
|
LLFloaterReg::hideInstance("prefs_translation");
|
||||||
|
|
||||||
// hide translation settings floater
|
// hide autoreplace settings floater
|
||||||
LLFloaterReg::hideInstance("prefs_autoreplace");
|
LLFloaterReg::hideInstance("prefs_autoreplace");
|
||||||
|
|
||||||
|
// hide spellchecker settings folder
|
||||||
|
LLFloaterReg::hideInstance("prefs_spellchecker");
|
||||||
|
|
||||||
// cancel hardware menu
|
// cancel hardware menu
|
||||||
LLFloaterHardwareSettings* hardware_settings = LLFloaterReg::getTypedInstance<LLFloaterHardwareSettings>("prefs_hardware_settings");
|
LLFloaterHardwareSettings* hardware_settings = LLFloaterReg::getTypedInstance<LLFloaterHardwareSettings>("prefs_hardware_settings");
|
||||||
if (hardware_settings)
|
if (hardware_settings)
|
||||||
|
|
|
||||||
|
|
@ -1734,7 +1734,7 @@ void LLPanelEstateInfo::accessAddCore3(const uuid_vec_t& ids, void* data)
|
||||||
LLSD args;
|
LLSD args;
|
||||||
args["NUM_ADDED"] = llformat("%d",ids.size());
|
args["NUM_ADDED"] = llformat("%d",ids.size());
|
||||||
args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS);
|
args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS);
|
||||||
args["LIST_TYPE"] = "Allowed Residents";
|
args["LIST_TYPE"] = LLTrans::getString("RegionInfoListTypeAllowedAgents");
|
||||||
args["NUM_EXCESS"] = llformat("%d",(ids.size()+currentCount)-ESTATE_MAX_ACCESS_IDS);
|
args["NUM_EXCESS"] = llformat("%d",(ids.size()+currentCount)-ESTATE_MAX_ACCESS_IDS);
|
||||||
LLNotificationsUtil::add("MaxAgentOnRegionBatch", args);
|
LLNotificationsUtil::add("MaxAgentOnRegionBatch", args);
|
||||||
delete change_info;
|
delete change_info;
|
||||||
|
|
@ -1750,7 +1750,7 @@ void LLPanelEstateInfo::accessAddCore3(const uuid_vec_t& ids, void* data)
|
||||||
LLSD args;
|
LLSD args;
|
||||||
args["NUM_ADDED"] = llformat("%d",ids.size());
|
args["NUM_ADDED"] = llformat("%d",ids.size());
|
||||||
args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS);
|
args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS);
|
||||||
args["LIST_TYPE"] = "Banned Residents";
|
args["LIST_TYPE"] = LLTrans::getString("RegionInfoListTypeBannedAgents");
|
||||||
args["NUM_EXCESS"] = llformat("%d",(ids.size()+currentCount)-ESTATE_MAX_ACCESS_IDS);
|
args["NUM_EXCESS"] = llformat("%d",(ids.size()+currentCount)-ESTATE_MAX_ACCESS_IDS);
|
||||||
LLNotificationsUtil::add("MaxAgentOnRegionBatch", args);
|
LLNotificationsUtil::add("MaxAgentOnRegionBatch", args);
|
||||||
delete change_info;
|
delete change_info;
|
||||||
|
|
@ -2815,9 +2815,10 @@ bool LLDispatchSetEstateAccess::operator()(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string msg = llformat("Banned residents: (%d, max %d)",
|
LLStringUtil::format_map_t args;
|
||||||
totalBannedAgents,
|
args["[BANNEDAGENTS]"] = llformat("%d", totalBannedAgents);
|
||||||
ESTATE_MAX_ACCESS_IDS);
|
args["[MAXBANNED]"] = llformat("%d", ESTATE_MAX_ACCESS_IDS);
|
||||||
|
std::string msg = LLTrans::getString("RegionInfoBannedResidents", args);
|
||||||
panel->getChild<LLUICtrl>("ban_resident_label")->setValue(LLSD(msg));
|
panel->getChild<LLUICtrl>("ban_resident_label")->setValue(LLSD(msg));
|
||||||
|
|
||||||
if (banned_agent_name_list)
|
if (banned_agent_name_list)
|
||||||
|
|
@ -2837,9 +2838,10 @@ bool LLDispatchSetEstateAccess::operator()(
|
||||||
|
|
||||||
if (access_flags & ESTATE_ACCESS_MANAGERS)
|
if (access_flags & ESTATE_ACCESS_MANAGERS)
|
||||||
{
|
{
|
||||||
std::string msg = llformat("Estate Managers: (%d, max %d)",
|
LLStringUtil::format_map_t args;
|
||||||
num_estate_managers,
|
args["[ESTATEMANAGERS]"] = llformat("%d", num_estate_managers);
|
||||||
ESTATE_MAX_MANAGERS);
|
args["[MAXMANAGERS]"] = llformat("%d", ESTATE_MAX_MANAGERS);
|
||||||
|
std::string msg = LLTrans::getString("RegionInfoEstateManagers", args);
|
||||||
panel->getChild<LLUICtrl>("estate_manager_label")->setValue(LLSD(msg));
|
panel->getChild<LLUICtrl>("estate_manager_label")->setValue(LLSD(msg));
|
||||||
|
|
||||||
LLNameListCtrl* estate_manager_name_list =
|
LLNameListCtrl* estate_manager_name_list =
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -27,7 +27,6 @@
|
||||||
#ifndef LL_LLFLOATERSNAPSHOT_H
|
#ifndef LL_LLFLOATERSNAPSHOT_H
|
||||||
#define LL_LLFLOATERSNAPSHOT_H
|
#define LL_LLFLOATERSNAPSHOT_H
|
||||||
|
|
||||||
#include "llimage.h"
|
|
||||||
#include "llfloater.h"
|
#include "llfloater.h"
|
||||||
|
|
||||||
class LLSpinCtrl;
|
class LLSpinCtrl;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,920 @@
|
||||||
|
/**
|
||||||
|
* @file llfloatersocial.cpp
|
||||||
|
* @brief Implementation of llfloatersocial
|
||||||
|
* @author Gilbert@lindenlab.com
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
|
||||||
|
* Second Life Viewer Source Code
|
||||||
|
* Copyright (C) 2013, Linden Research, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation;
|
||||||
|
* version 2.1 of the License only.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
|
* $/LicenseInfo$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "llviewerprecompiledheaders.h"
|
||||||
|
|
||||||
|
#include "llfloatersocial.h"
|
||||||
|
|
||||||
|
#include "llagent.h"
|
||||||
|
#include "llagentui.h"
|
||||||
|
#include "llcheckboxctrl.h"
|
||||||
|
#include "llcombobox.h"
|
||||||
|
#include "llfacebookconnect.h"
|
||||||
|
#include "llfloaterreg.h"
|
||||||
|
#include "lliconctrl.h"
|
||||||
|
#include "llresmgr.h" // LLLocale
|
||||||
|
#include "llsdserialize.h"
|
||||||
|
#include "llloadingindicator.h"
|
||||||
|
#include "llplugincookiestore.h"
|
||||||
|
#include "llslurl.h"
|
||||||
|
#include "lltrans.h"
|
||||||
|
#include "llsnapshotlivepreview.h"
|
||||||
|
#include "llviewerregion.h"
|
||||||
|
#include "llviewercontrol.h"
|
||||||
|
#include "llviewermedia.h"
|
||||||
|
|
||||||
|
static LLRegisterPanelClassWrapper<LLSocialStatusPanel> t_panel_status("llsocialstatuspanel");
|
||||||
|
static LLRegisterPanelClassWrapper<LLSocialPhotoPanel> t_panel_photo("llsocialphotopanel");
|
||||||
|
static LLRegisterPanelClassWrapper<LLSocialCheckinPanel> t_panel_checkin("llsocialcheckinpanel");
|
||||||
|
static LLRegisterPanelClassWrapper<LLSocialAccountPanel> t_panel_account("llsocialaccountpanel");
|
||||||
|
|
||||||
|
const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte
|
||||||
|
const std::string DEFAULT_CHECKIN_LOCATION_URL = "http://maps.secondlife.com/";
|
||||||
|
const std::string DEFAULT_CHECKIN_ICON_URL = "http://map.secondlife.com.s3.amazonaws.com/map_placeholder.png";
|
||||||
|
const std::string DEFAULT_CHECKIN_QUERY_PARAMETERS = "?sourceid=slshare_checkin&utm_source=facebook&utm_medium=checkin&utm_campaign=slshare";
|
||||||
|
const std::string DEFAULT_PHOTO_QUERY_PARAMETERS = "?sourceid=slshare_photo&utm_source=facebook&utm_medium=photo&utm_campaign=slshare";
|
||||||
|
|
||||||
|
std::string get_map_url()
|
||||||
|
{
|
||||||
|
LLVector3d center_agent;
|
||||||
|
if (gAgent.getRegion())
|
||||||
|
{
|
||||||
|
center_agent = gAgent.getRegion()->getCenterGlobal();
|
||||||
|
}
|
||||||
|
int x_pos = center_agent[0] / 256.0;
|
||||||
|
int y_pos = center_agent[1] / 256.0;
|
||||||
|
std::string map_url = gSavedSettings.getString("CurrentMapServerURL") + llformat("map-1-%d-%d-objects.jpg", x_pos, y_pos);
|
||||||
|
return map_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////
|
||||||
|
//LLSocialStatusPanel//////
|
||||||
|
///////////////////////////
|
||||||
|
|
||||||
|
LLSocialStatusPanel::LLSocialStatusPanel() :
|
||||||
|
mMessageTextEditor(NULL),
|
||||||
|
mPostButton(NULL),
|
||||||
|
mCancelButton(NULL)
|
||||||
|
{
|
||||||
|
mCommitCallbackRegistrar.add("SocialSharing.SendStatus", boost::bind(&LLSocialStatusPanel::onSend, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL LLSocialStatusPanel::postBuild()
|
||||||
|
{
|
||||||
|
mMessageTextEditor = getChild<LLUICtrl>("status_message");
|
||||||
|
mPostButton = getChild<LLUICtrl>("post_status_btn");
|
||||||
|
mCancelButton = getChild<LLUICtrl>("cancel_status_btn");
|
||||||
|
|
||||||
|
return LLPanel::postBuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialStatusPanel::draw()
|
||||||
|
{
|
||||||
|
if (mMessageTextEditor && mPostButton && mCancelButton)
|
||||||
|
{
|
||||||
|
bool no_ongoing_connection = !(LLFacebookConnect::instance().isTransactionOngoing());
|
||||||
|
std::string message = mMessageTextEditor->getValue().asString();
|
||||||
|
mMessageTextEditor->setEnabled(no_ongoing_connection);
|
||||||
|
mCancelButton->setEnabled(no_ongoing_connection);
|
||||||
|
mPostButton->setEnabled(no_ongoing_connection && !message.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
LLPanel::draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialStatusPanel::onSend()
|
||||||
|
{
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialStatusPanel"); // just in case it is already listening
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectState").listen("LLSocialStatusPanel", boost::bind(&LLSocialStatusPanel::onFacebookConnectStateChange, this, _1));
|
||||||
|
|
||||||
|
// Connect to Facebook if necessary and then post
|
||||||
|
if (LLFacebookConnect::instance().isConnected())
|
||||||
|
{
|
||||||
|
sendStatus();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().checkConnectionToFacebook(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LLSocialStatusPanel::onFacebookConnectStateChange(const LLSD& data)
|
||||||
|
{
|
||||||
|
switch (data.get("enum").asInteger())
|
||||||
|
{
|
||||||
|
case LLFacebookConnect::FB_CONNECTED:
|
||||||
|
sendStatus();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LLFacebookConnect::FB_POSTED:
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialStatusPanel");
|
||||||
|
clearAndClose();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialStatusPanel::sendStatus()
|
||||||
|
{
|
||||||
|
std::string message = mMessageTextEditor->getValue().asString();
|
||||||
|
if (!message.empty())
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().updateStatus(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialStatusPanel::clearAndClose()
|
||||||
|
{
|
||||||
|
mMessageTextEditor->setValue("");
|
||||||
|
|
||||||
|
LLFloater* floater = getParentByType<LLFloater>();
|
||||||
|
if (floater)
|
||||||
|
{
|
||||||
|
floater->closeFloater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////
|
||||||
|
//LLSocialPhotoPanel///////
|
||||||
|
///////////////////////////
|
||||||
|
|
||||||
|
LLSocialPhotoPanel::LLSocialPhotoPanel() :
|
||||||
|
mSnapshotPanel(NULL),
|
||||||
|
mResolutionComboBox(NULL),
|
||||||
|
mRefreshBtn(NULL),
|
||||||
|
mWorkingLabel(NULL),
|
||||||
|
mThumbnailPlaceholder(NULL),
|
||||||
|
mCaptionTextBox(NULL),
|
||||||
|
mLocationCheckbox(NULL),
|
||||||
|
mPostButton(NULL)
|
||||||
|
{
|
||||||
|
mCommitCallbackRegistrar.add("SocialSharing.SendPhoto", boost::bind(&LLSocialPhotoPanel::onSend, this));
|
||||||
|
mCommitCallbackRegistrar.add("SocialSharing.RefreshPhoto", boost::bind(&LLSocialPhotoPanel::onClickNewSnapshot, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
LLSocialPhotoPanel::~LLSocialPhotoPanel()
|
||||||
|
{
|
||||||
|
if(mPreviewHandle.get())
|
||||||
|
{
|
||||||
|
mPreviewHandle.get()->die();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL LLSocialPhotoPanel::postBuild()
|
||||||
|
{
|
||||||
|
setVisibleCallback(boost::bind(&LLSocialPhotoPanel::onVisibilityChange, this, _2));
|
||||||
|
|
||||||
|
mSnapshotPanel = getChild<LLUICtrl>("snapshot_panel");
|
||||||
|
mResolutionComboBox = getChild<LLUICtrl>("resolution_combobox");
|
||||||
|
mResolutionComboBox->setCommitCallback(boost::bind(&LLSocialPhotoPanel::updateResolution, this, TRUE));
|
||||||
|
mRefreshBtn = getChild<LLUICtrl>("new_snapshot_btn");
|
||||||
|
mWorkingLabel = getChild<LLUICtrl>("working_lbl");
|
||||||
|
mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder");
|
||||||
|
mCaptionTextBox = getChild<LLUICtrl>("photo_caption");
|
||||||
|
mLocationCheckbox = getChild<LLUICtrl>("add_location_cb");
|
||||||
|
mPostButton = getChild<LLUICtrl>("post_photo_btn");
|
||||||
|
mCancelButton = getChild<LLUICtrl>("cancel_photo_btn");
|
||||||
|
|
||||||
|
return LLPanel::postBuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialPhotoPanel::draw()
|
||||||
|
{
|
||||||
|
LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get());
|
||||||
|
|
||||||
|
// Enable interaction only if no transaction with the service is on-going (prevent duplicated posts)
|
||||||
|
bool no_ongoing_connection = !(LLFacebookConnect::instance().isTransactionOngoing());
|
||||||
|
mCancelButton->setEnabled(no_ongoing_connection);
|
||||||
|
mCaptionTextBox->setEnabled(no_ongoing_connection);
|
||||||
|
mResolutionComboBox->setEnabled(no_ongoing_connection);
|
||||||
|
mRefreshBtn->setEnabled(no_ongoing_connection);
|
||||||
|
mLocationCheckbox->setEnabled(no_ongoing_connection);
|
||||||
|
|
||||||
|
// Display the preview if one is available
|
||||||
|
if (previewp && previewp->getThumbnailImage())
|
||||||
|
{
|
||||||
|
const LLRect& thumbnail_rect = mThumbnailPlaceholder->getRect();
|
||||||
|
const S32 thumbnail_w = previewp->getThumbnailWidth();
|
||||||
|
const S32 thumbnail_h = previewp->getThumbnailHeight();
|
||||||
|
|
||||||
|
// calc preview offset within the preview rect
|
||||||
|
const S32 local_offset_x = (thumbnail_rect.getWidth() - thumbnail_w) / 2 ;
|
||||||
|
const S32 local_offset_y = (thumbnail_rect.getHeight() - thumbnail_h) / 2 ;
|
||||||
|
|
||||||
|
// calc preview offset within the floater rect
|
||||||
|
// Hack : To get the full offset, we need to take into account each and every offset of each widgets up to the floater.
|
||||||
|
// This is almost as arbitrary as using a fixed offset so that's what we do here for the sake of simplicity.
|
||||||
|
// *TODO : Get the offset looking through the hierarchy of widgets, should be done in postBuild() so to avoid traversing the hierarchy each time.
|
||||||
|
S32 offset_x = thumbnail_rect.mLeft + local_offset_x - 1;
|
||||||
|
S32 offset_y = thumbnail_rect.mBottom + local_offset_y - 39;
|
||||||
|
|
||||||
|
mSnapshotPanel->localPointToOtherView(offset_x, offset_y, &offset_x, &offset_y, getParentByType<LLFloater>());
|
||||||
|
|
||||||
|
gGL.matrixMode(LLRender::MM_MODELVIEW);
|
||||||
|
// Apply floater transparency to the texture unless the floater is focused.
|
||||||
|
F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
|
||||||
|
LLColor4 color = LLColor4::white;
|
||||||
|
gl_draw_scaled_image(offset_x, offset_y,
|
||||||
|
thumbnail_w, thumbnail_h,
|
||||||
|
previewp->getThumbnailImage(), color % alpha);
|
||||||
|
|
||||||
|
previewp->drawPreviewRect(offset_x, offset_y) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the visibility of the working (computing preview) label
|
||||||
|
mWorkingLabel->setVisible(!(previewp && previewp->getSnapshotUpToDate()));
|
||||||
|
|
||||||
|
// Enable Post if we have a preview to send and no on going connection being processed
|
||||||
|
mPostButton->setEnabled(no_ongoing_connection && (previewp && previewp->getSnapshotUpToDate()));
|
||||||
|
|
||||||
|
// Draw the rest of the panel on top of it
|
||||||
|
LLPanel::draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
LLSnapshotLivePreview* LLSocialPhotoPanel::getPreviewView()
|
||||||
|
{
|
||||||
|
LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)mPreviewHandle.get();
|
||||||
|
return previewp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialPhotoPanel::onVisibilityChange(const LLSD& new_visibility)
|
||||||
|
{
|
||||||
|
bool visible = new_visibility.asBoolean();
|
||||||
|
if (visible)
|
||||||
|
{
|
||||||
|
if (mPreviewHandle.get())
|
||||||
|
{
|
||||||
|
LLSnapshotLivePreview* preview = getPreviewView();
|
||||||
|
if(preview)
|
||||||
|
{
|
||||||
|
lldebugs << "opened, updating snapshot" << llendl;
|
||||||
|
preview->updateSnapshot(TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LLRect full_screen_rect = getRootView()->getRect();
|
||||||
|
LLSnapshotLivePreview::Params p;
|
||||||
|
p.rect(full_screen_rect);
|
||||||
|
LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(p);
|
||||||
|
mPreviewHandle = previewp->getHandle();
|
||||||
|
|
||||||
|
previewp->setSnapshotType(previewp->SNAPSHOT_WEB);
|
||||||
|
previewp->setSnapshotFormat(LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG);
|
||||||
|
//previewp->setSnapshotQuality(98);
|
||||||
|
previewp->setThumbnailPlaceholderRect(mThumbnailPlaceholder->getRect());
|
||||||
|
|
||||||
|
updateControls();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialPhotoPanel::onClickNewSnapshot()
|
||||||
|
{
|
||||||
|
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||||
|
if (previewp)
|
||||||
|
{
|
||||||
|
//setStatus(Impl::STATUS_READY);
|
||||||
|
lldebugs << "updating snapshot" << llendl;
|
||||||
|
previewp->updateSnapshot(TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialPhotoPanel::onSend()
|
||||||
|
{
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialPhotoPanel"); // just in case it is already listening
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectState").listen("LLSocialPhotoPanel", boost::bind(&LLSocialPhotoPanel::onFacebookConnectStateChange, this, _1));
|
||||||
|
|
||||||
|
// Connect to Facebook if necessary and then post
|
||||||
|
if (LLFacebookConnect::instance().isConnected())
|
||||||
|
{
|
||||||
|
sendPhoto();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().checkConnectionToFacebook(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LLSocialPhotoPanel::onFacebookConnectStateChange(const LLSD& data)
|
||||||
|
{
|
||||||
|
switch (data.get("enum").asInteger())
|
||||||
|
{
|
||||||
|
case LLFacebookConnect::FB_CONNECTED:
|
||||||
|
sendPhoto();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LLFacebookConnect::FB_POSTED:
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialPhotoPanel");
|
||||||
|
clearAndClose();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialPhotoPanel::sendPhoto()
|
||||||
|
{
|
||||||
|
// Get the caption
|
||||||
|
std::string caption = mCaptionTextBox->getValue().asString();
|
||||||
|
|
||||||
|
// Add the location if required
|
||||||
|
bool add_location = mLocationCheckbox->getValue().asBoolean();
|
||||||
|
if (add_location)
|
||||||
|
{
|
||||||
|
// Get the SLURL for the location
|
||||||
|
LLSLURL slurl;
|
||||||
|
LLAgentUI::buildSLURL(slurl);
|
||||||
|
std::string slurl_string = slurl.getSLURLString();
|
||||||
|
|
||||||
|
// Add query parameters so Google Analytics can track incoming clicks!
|
||||||
|
slurl_string += DEFAULT_PHOTO_QUERY_PARAMETERS;
|
||||||
|
|
||||||
|
// Add it to the caption (pretty crude, but we don't have a better option with photos)
|
||||||
|
if (caption.empty())
|
||||||
|
caption = slurl_string;
|
||||||
|
else
|
||||||
|
caption = caption + " " + slurl_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the image
|
||||||
|
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||||
|
|
||||||
|
// Post to Facebook
|
||||||
|
LLFacebookConnect::instance().sharePhoto(previewp->getFormattedImage(), caption);
|
||||||
|
|
||||||
|
updateControls();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialPhotoPanel::clearAndClose()
|
||||||
|
{
|
||||||
|
mCaptionTextBox->setValue("");
|
||||||
|
|
||||||
|
LLFloater* floater = getParentByType<LLFloater>();
|
||||||
|
if (floater)
|
||||||
|
{
|
||||||
|
floater->closeFloater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialPhotoPanel::updateControls()
|
||||||
|
{
|
||||||
|
LLSnapshotLivePreview* previewp = getPreviewView();
|
||||||
|
BOOL got_bytes = previewp && previewp->getDataSize() > 0;
|
||||||
|
BOOL got_snap = previewp && previewp->getSnapshotUpToDate();
|
||||||
|
LLSnapshotLivePreview::ESnapshotType shot_type = (previewp ? previewp->getSnapshotType() : LLSnapshotLivePreview::SNAPSHOT_POSTCARD);
|
||||||
|
|
||||||
|
// *TODO: Separate maximum size for Web images from postcards
|
||||||
|
lldebugs << "Is snapshot up-to-date? " << got_snap << llendl;
|
||||||
|
|
||||||
|
LLLocale locale(LLLocale::USER_LOCALE);
|
||||||
|
std::string bytes_string;
|
||||||
|
if (got_snap)
|
||||||
|
{
|
||||||
|
LLResMgr::getInstance()->getIntegerString(bytes_string, (previewp->getDataSize()) >> 10 );
|
||||||
|
}
|
||||||
|
|
||||||
|
//getChild<LLUICtrl>("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : getString("unknown")); <---uses localized string
|
||||||
|
getChild<LLUICtrl>("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : "unknown");
|
||||||
|
getChild<LLUICtrl>("file_size_label")->setColor(
|
||||||
|
shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD
|
||||||
|
&& got_bytes
|
||||||
|
&& previewp->getDataSize() > MAX_POSTCARD_DATASIZE ? LLUIColor(LLColor4::red) : LLUIColorTable::instance().getColor( "LabelTextColor" ));
|
||||||
|
|
||||||
|
updateResolution(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialPhotoPanel::updateResolution(BOOL do_update)
|
||||||
|
{
|
||||||
|
LLComboBox* combobox = static_cast<LLComboBox *>(mResolutionComboBox);
|
||||||
|
|
||||||
|
std::string sdstring = combobox->getSelectedValue();
|
||||||
|
LLSD sdres;
|
||||||
|
std::stringstream sstream(sdstring);
|
||||||
|
LLSDSerialize::fromNotation(sdres, sstream, sdstring.size());
|
||||||
|
|
||||||
|
S32 width = sdres[0];
|
||||||
|
S32 height = sdres[1];
|
||||||
|
|
||||||
|
LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get());
|
||||||
|
if (previewp && combobox->getCurrentIndex() >= 0)
|
||||||
|
{
|
||||||
|
S32 original_width = 0 , original_height = 0 ;
|
||||||
|
previewp->getSize(original_width, original_height) ;
|
||||||
|
|
||||||
|
if (width == 0 || height == 0)
|
||||||
|
{
|
||||||
|
// take resolution from current window size
|
||||||
|
lldebugs << "Setting preview res from window: " << gViewerWindow->getWindowWidthRaw() << "x" << gViewerWindow->getWindowHeightRaw() << llendl;
|
||||||
|
previewp->setSize(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// use the resolution from the selected pre-canned drop-down choice
|
||||||
|
lldebugs << "Setting preview res selected from combo: " << width << "x" << height << llendl;
|
||||||
|
previewp->setSize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkAspectRatio(width);
|
||||||
|
|
||||||
|
previewp->getSize(width, height);
|
||||||
|
|
||||||
|
if(original_width != width || original_height != height)
|
||||||
|
{
|
||||||
|
previewp->setSize(width, height);
|
||||||
|
|
||||||
|
// hide old preview as the aspect ratio could be wrong
|
||||||
|
lldebugs << "updating thumbnail" << llendl;
|
||||||
|
|
||||||
|
previewp->updateSnapshot(FALSE, TRUE);
|
||||||
|
if(do_update)
|
||||||
|
{
|
||||||
|
lldebugs << "Will update controls" << llendl;
|
||||||
|
updateControls();
|
||||||
|
LLSocialPhotoPanel::onClickNewSnapshot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialPhotoPanel::checkAspectRatio(S32 index)
|
||||||
|
{
|
||||||
|
LLSnapshotLivePreview *previewp = getPreviewView() ;
|
||||||
|
|
||||||
|
BOOL keep_aspect = FALSE;
|
||||||
|
|
||||||
|
if (0 == index) // current window size
|
||||||
|
{
|
||||||
|
keep_aspect = TRUE;
|
||||||
|
}
|
||||||
|
else // predefined resolution
|
||||||
|
{
|
||||||
|
keep_aspect = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previewp)
|
||||||
|
{
|
||||||
|
previewp->mKeepAspectRatio = keep_aspect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LLUICtrl* LLSocialPhotoPanel::getRefreshBtn()
|
||||||
|
{
|
||||||
|
return mRefreshBtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////
|
||||||
|
//LLSocialCheckinPanel//
|
||||||
|
////////////////////////
|
||||||
|
|
||||||
|
LLSocialCheckinPanel::LLSocialCheckinPanel() :
|
||||||
|
mMapUrl(""),
|
||||||
|
mReloadingMapTexture(false)
|
||||||
|
{
|
||||||
|
mCommitCallbackRegistrar.add("SocialSharing.SendCheckin", boost::bind(&LLSocialCheckinPanel::onSend, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL LLSocialCheckinPanel::postBuild()
|
||||||
|
{
|
||||||
|
// Keep pointers to widgets so we don't traverse the UI hierarchy too often
|
||||||
|
mPostButton = getChild<LLUICtrl>("post_place_btn");
|
||||||
|
mCancelButton = getChild<LLUICtrl>("cancel_place_btn");
|
||||||
|
mMessageTextEditor = getChild<LLUICtrl>("place_caption");
|
||||||
|
mMapLoadingIndicator = getChild<LLUICtrl>("map_loading_indicator");
|
||||||
|
mMapPlaceholder = getChild<LLIconCtrl>("map_placeholder");
|
||||||
|
mMapDefault = getChild<LLIconCtrl>("map_default");
|
||||||
|
mMapCheckBox = getChild<LLCheckBoxCtrl>("add_place_view_cb");
|
||||||
|
|
||||||
|
return LLPanel::postBuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialCheckinPanel::draw()
|
||||||
|
{
|
||||||
|
bool no_ongoing_connection = !(LLFacebookConnect::instance().isTransactionOngoing());
|
||||||
|
mPostButton->setEnabled(no_ongoing_connection);
|
||||||
|
mCancelButton->setEnabled(no_ongoing_connection);
|
||||||
|
mMessageTextEditor->setEnabled(no_ongoing_connection);
|
||||||
|
mMapCheckBox->setEnabled(no_ongoing_connection);
|
||||||
|
|
||||||
|
std::string map_url = get_map_url();
|
||||||
|
// Did we change location?
|
||||||
|
if (map_url != mMapUrl)
|
||||||
|
{
|
||||||
|
mMapUrl = map_url;
|
||||||
|
// Load the map tile
|
||||||
|
mMapTexture = LLViewerTextureManager::getFetchedTextureFromUrl(mMapUrl, FTT_MAP_TILE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
|
||||||
|
mMapTexture->setBoostLevel(LLGLTexture::BOOST_MAP);
|
||||||
|
mReloadingMapTexture = true;
|
||||||
|
// In the meantime, put the "loading" indicator on, hide the tile map and disable the checkbox
|
||||||
|
mMapLoadingIndicator->setVisible(true);
|
||||||
|
mMapPlaceholder->setVisible(false);
|
||||||
|
}
|
||||||
|
// Are we done loading the map tile?
|
||||||
|
if (mReloadingMapTexture && mMapTexture->isFullyLoaded())
|
||||||
|
{
|
||||||
|
// Don't do it again next time around
|
||||||
|
mReloadingMapTexture = false;
|
||||||
|
// Convert the map texture to the appropriate image object
|
||||||
|
LLPointer<LLUIImage> ui_image = new LLUIImage(mMapUrl, mMapTexture);
|
||||||
|
// Load the map widget with the correct map tile image
|
||||||
|
mMapPlaceholder->setImage(ui_image);
|
||||||
|
// Now hide the loading indicator, bring the tile in view and reenable the checkbox with its previous value
|
||||||
|
mMapLoadingIndicator->setVisible(false);
|
||||||
|
mMapPlaceholder->setVisible(true);
|
||||||
|
}
|
||||||
|
// Show the default icon if that's the checkbox value (the real one...)
|
||||||
|
// This will hide/show the loading indicator and/or tile underneath
|
||||||
|
mMapDefault->setVisible(!(mMapCheckBox->get()));
|
||||||
|
|
||||||
|
LLPanel::draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialCheckinPanel::onSend()
|
||||||
|
{
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialCheckinPanel"); // just in case it is already listening
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectState").listen("LLSocialCheckinPanel", boost::bind(&LLSocialCheckinPanel::onFacebookConnectStateChange, this, _1));
|
||||||
|
|
||||||
|
// Connect to Facebook if necessary and then post
|
||||||
|
if (LLFacebookConnect::instance().isConnected())
|
||||||
|
{
|
||||||
|
sendCheckin();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().checkConnectionToFacebook(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LLSocialCheckinPanel::onFacebookConnectStateChange(const LLSD& data)
|
||||||
|
{
|
||||||
|
switch (data.get("enum").asInteger())
|
||||||
|
{
|
||||||
|
case LLFacebookConnect::FB_CONNECTED:
|
||||||
|
sendCheckin();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LLFacebookConnect::FB_POSTED:
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialCheckinPanel");
|
||||||
|
clearAndClose();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialCheckinPanel::sendCheckin()
|
||||||
|
{
|
||||||
|
// Get the location SLURL
|
||||||
|
LLSLURL slurl;
|
||||||
|
LLAgentUI::buildSLURL(slurl);
|
||||||
|
std::string slurl_string = slurl.getSLURLString();
|
||||||
|
|
||||||
|
// Use a valid http:// URL if the scheme is secondlife://
|
||||||
|
LLURI slurl_uri(slurl_string);
|
||||||
|
if (slurl_uri.scheme() == LLSLURL::SLURL_SECONDLIFE_SCHEME)
|
||||||
|
{
|
||||||
|
slurl_string = DEFAULT_CHECKIN_LOCATION_URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add query parameters so Google Analytics can track incoming clicks!
|
||||||
|
slurl_string += DEFAULT_CHECKIN_QUERY_PARAMETERS;
|
||||||
|
|
||||||
|
// Get the region name
|
||||||
|
std::string region_name = gAgent.getRegion()->getName();
|
||||||
|
|
||||||
|
// Get the region description
|
||||||
|
std::string description;
|
||||||
|
LLAgentUI::buildLocationString(description, LLAgentUI::LOCATION_FORMAT_NORMAL_COORDS, gAgent.getPositionAgent());
|
||||||
|
|
||||||
|
// Optionally add the region map view
|
||||||
|
bool add_map_view = mMapCheckBox->getValue().asBoolean();
|
||||||
|
std::string map_url = (add_map_view ? get_map_url() : DEFAULT_CHECKIN_ICON_URL);
|
||||||
|
|
||||||
|
// Get the caption
|
||||||
|
std::string caption = mMessageTextEditor->getValue().asString();
|
||||||
|
|
||||||
|
// Post to Facebook
|
||||||
|
LLFacebookConnect::instance().postCheckin(slurl_string, region_name, description, map_url, caption);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialCheckinPanel::clearAndClose()
|
||||||
|
{
|
||||||
|
mMessageTextEditor->setValue("");
|
||||||
|
|
||||||
|
LLFloater* floater = getParentByType<LLFloater>();
|
||||||
|
if (floater)
|
||||||
|
{
|
||||||
|
floater->closeFloater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////
|
||||||
|
//LLSocialAccountPanel//////
|
||||||
|
///////////////////////////
|
||||||
|
|
||||||
|
LLSocialAccountPanel::LLSocialAccountPanel() :
|
||||||
|
mAccountCaptionLabel(NULL),
|
||||||
|
mAccountNameLabel(NULL),
|
||||||
|
mPanelButtons(NULL),
|
||||||
|
mConnectButton(NULL),
|
||||||
|
mDisconnectButton(NULL)
|
||||||
|
{
|
||||||
|
mCommitCallbackRegistrar.add("SocialSharing.Connect", boost::bind(&LLSocialAccountPanel::onConnect, this));
|
||||||
|
mCommitCallbackRegistrar.add("SocialSharing.Disconnect", boost::bind(&LLSocialAccountPanel::onDisconnect, this));
|
||||||
|
|
||||||
|
setVisibleCallback(boost::bind(&LLSocialAccountPanel::onVisibilityChange, this, _2));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL LLSocialAccountPanel::postBuild()
|
||||||
|
{
|
||||||
|
mAccountCaptionLabel = getChild<LLTextBox>("account_caption_label");
|
||||||
|
mAccountNameLabel = getChild<LLTextBox>("account_name_label");
|
||||||
|
mPanelButtons = getChild<LLUICtrl>("panel_buttons");
|
||||||
|
mConnectButton = getChild<LLUICtrl>("connect_btn");
|
||||||
|
mDisconnectButton = getChild<LLUICtrl>("disconnect_btn");
|
||||||
|
|
||||||
|
return LLPanel::postBuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialAccountPanel::draw()
|
||||||
|
{
|
||||||
|
LLFacebookConnect::EConnectionState connection_state = LLFacebookConnect::instance().getConnectionState();
|
||||||
|
|
||||||
|
//Disable the 'disconnect' button and the 'use another account' button when disconnecting in progress
|
||||||
|
bool disconnecting = connection_state == LLFacebookConnect::FB_DISCONNECTING;
|
||||||
|
mDisconnectButton->setEnabled(!disconnecting);
|
||||||
|
|
||||||
|
//Disable the 'connect' button when a connection is in progress
|
||||||
|
bool connecting = connection_state == LLFacebookConnect::FB_CONNECTION_IN_PROGRESS;
|
||||||
|
mConnectButton->setEnabled(!connecting);
|
||||||
|
|
||||||
|
LLPanel::draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialAccountPanel::onVisibilityChange(const LLSD& new_visibility)
|
||||||
|
{
|
||||||
|
bool visible = new_visibility.asBoolean();
|
||||||
|
|
||||||
|
if(visible)
|
||||||
|
{
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialAccountPanel");
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectState").listen("LLSocialAccountPanel", boost::bind(&LLSocialAccountPanel::onFacebookConnectStateChange, this, _1));
|
||||||
|
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectInfo").stopListening("LLSocialAccountPanel");
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectInfo").listen("LLSocialAccountPanel", boost::bind(&LLSocialAccountPanel::onFacebookConnectInfoChange, this));
|
||||||
|
|
||||||
|
//Connected
|
||||||
|
if(LLFacebookConnect::instance().isConnected())
|
||||||
|
{
|
||||||
|
showConnectedLayout();
|
||||||
|
}
|
||||||
|
//Check if connected (show disconnected layout in meantime)
|
||||||
|
else
|
||||||
|
{
|
||||||
|
showDisconnectedLayout();
|
||||||
|
}
|
||||||
|
if ((LLFacebookConnect::instance().getConnectionState() == LLFacebookConnect::FB_NOT_CONNECTED) ||
|
||||||
|
(LLFacebookConnect::instance().getConnectionState() == LLFacebookConnect::FB_CONNECTION_FAILED))
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().checkConnectionToFacebook();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLSocialAccountPanel");
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectInfo").stopListening("LLSocialAccountPanel");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LLSocialAccountPanel::onFacebookConnectStateChange(const LLSD& data)
|
||||||
|
{
|
||||||
|
if(LLFacebookConnect::instance().isConnected())
|
||||||
|
{
|
||||||
|
//In process of disconnecting so leave the layout as is
|
||||||
|
if(data.get("enum").asInteger() != LLFacebookConnect::FB_DISCONNECTING)
|
||||||
|
{
|
||||||
|
showConnectedLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
showDisconnectedLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LLSocialAccountPanel::onFacebookConnectInfoChange()
|
||||||
|
{
|
||||||
|
LLSD info = LLFacebookConnect::instance().getInfo();
|
||||||
|
std::string clickable_name;
|
||||||
|
|
||||||
|
//Strings of format [http://www.somewebsite.com Click Me] become clickable text
|
||||||
|
if(info.has("link") && info.has("name"))
|
||||||
|
{
|
||||||
|
clickable_name = "[" + info["link"].asString() + " " + info["name"].asString() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
mAccountNameLabel->setText(clickable_name);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialAccountPanel::showConnectButton()
|
||||||
|
{
|
||||||
|
if(!mConnectButton->getVisible())
|
||||||
|
{
|
||||||
|
mConnectButton->setVisible(TRUE);
|
||||||
|
mDisconnectButton->setVisible(FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialAccountPanel::hideConnectButton()
|
||||||
|
{
|
||||||
|
if(mConnectButton->getVisible())
|
||||||
|
{
|
||||||
|
mConnectButton->setVisible(FALSE);
|
||||||
|
mDisconnectButton->setVisible(TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialAccountPanel::showDisconnectedLayout()
|
||||||
|
{
|
||||||
|
mAccountCaptionLabel->setText(getString("facebook_disconnected"));
|
||||||
|
mAccountNameLabel->setText(std::string(""));
|
||||||
|
showConnectButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialAccountPanel::showConnectedLayout()
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().loadFacebookInfo();
|
||||||
|
|
||||||
|
mAccountCaptionLabel->setText(getString("facebook_connected"));
|
||||||
|
hideConnectButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialAccountPanel::onConnect()
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().checkConnectionToFacebook(true);
|
||||||
|
|
||||||
|
//Clear only the facebook browser cookies so that the facebook login screen appears
|
||||||
|
LLViewerMedia::getCookieStore()->removeCookiesByDomain(".facebook.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSocialAccountPanel::onDisconnect()
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().disconnectFromFacebook();
|
||||||
|
|
||||||
|
LLViewerMedia::getCookieStore()->removeCookiesByDomain(".facebook.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////
|
||||||
|
//LLFloaterSocial///////
|
||||||
|
////////////////////////
|
||||||
|
|
||||||
|
LLFloaterSocial::LLFloaterSocial(const LLSD& key) : LLFloater(key),
|
||||||
|
mSocialPhotoPanel(NULL),
|
||||||
|
mStatusErrorText(NULL),
|
||||||
|
mStatusLoadingText(NULL),
|
||||||
|
mStatusLoadingIndicator(NULL)
|
||||||
|
{
|
||||||
|
mCommitCallbackRegistrar.add("SocialSharing.Cancel", boost::bind(&LLFloaterSocial::onCancel, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFloaterSocial::onCancel()
|
||||||
|
{
|
||||||
|
closeFloater();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL LLFloaterSocial::postBuild()
|
||||||
|
{
|
||||||
|
// Keep tab of the Photo Panel
|
||||||
|
mSocialPhotoPanel = static_cast<LLSocialPhotoPanel*>(getChild<LLUICtrl>("panel_social_photo"));
|
||||||
|
// Connection status widgets
|
||||||
|
mStatusErrorText = getChild<LLTextBox>("connection_error_text");
|
||||||
|
mStatusLoadingText = getChild<LLTextBox>("connection_loading_text");
|
||||||
|
mStatusLoadingIndicator = getChild<LLUICtrl>("connection_loading_indicator");
|
||||||
|
return LLFloater::postBuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void LLFloaterSocial::preUpdate()
|
||||||
|
{
|
||||||
|
LLFloaterSocial* instance = LLFloaterReg::findTypedInstance<LLFloaterSocial>("social");
|
||||||
|
if (instance)
|
||||||
|
{
|
||||||
|
//Will set file size text to 'unknown'
|
||||||
|
instance->mSocialPhotoPanel->updateControls();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void LLFloaterSocial::postUpdate()
|
||||||
|
{
|
||||||
|
LLFloaterSocial* instance = LLFloaterReg::findTypedInstance<LLFloaterSocial>("social");
|
||||||
|
if (instance)
|
||||||
|
{
|
||||||
|
//Will set the file size text
|
||||||
|
instance->mSocialPhotoPanel->updateControls();
|
||||||
|
|
||||||
|
// The refresh button is initially hidden. We show it after the first update,
|
||||||
|
// i.e. after snapshot is taken
|
||||||
|
LLUICtrl * refresh_button = instance->mSocialPhotoPanel->getRefreshBtn();
|
||||||
|
|
||||||
|
if (!refresh_button->getVisible())
|
||||||
|
{
|
||||||
|
refresh_button->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFloaterSocial::draw()
|
||||||
|
{
|
||||||
|
if (mStatusErrorText && mStatusLoadingText && mStatusLoadingIndicator)
|
||||||
|
{
|
||||||
|
mStatusErrorText->setVisible(false);
|
||||||
|
mStatusLoadingText->setVisible(false);
|
||||||
|
mStatusLoadingIndicator->setVisible(false);
|
||||||
|
LLFacebookConnect::EConnectionState connection_state = LLFacebookConnect::instance().getConnectionState();
|
||||||
|
std::string status_text;
|
||||||
|
|
||||||
|
switch (connection_state)
|
||||||
|
{
|
||||||
|
case LLFacebookConnect::FB_NOT_CONNECTED:
|
||||||
|
// No status displayed when first opening the panel and no connection done
|
||||||
|
case LLFacebookConnect::FB_CONNECTED:
|
||||||
|
// When successfully connected, no message is displayed
|
||||||
|
case LLFacebookConnect::FB_POSTED:
|
||||||
|
// No success message to show since we actually close the floater after successful posting completion
|
||||||
|
break;
|
||||||
|
case LLFacebookConnect::FB_CONNECTION_IN_PROGRESS:
|
||||||
|
// Connection loading indicator
|
||||||
|
mStatusLoadingText->setVisible(true);
|
||||||
|
status_text = LLTrans::getString("SocialFacebookConnecting");
|
||||||
|
mStatusLoadingText->setValue(status_text);
|
||||||
|
mStatusLoadingIndicator->setVisible(true);
|
||||||
|
break;
|
||||||
|
case LLFacebookConnect::FB_POSTING:
|
||||||
|
// Posting indicator
|
||||||
|
mStatusLoadingText->setVisible(true);
|
||||||
|
status_text = LLTrans::getString("SocialFacebookPosting");
|
||||||
|
mStatusLoadingText->setValue(status_text);
|
||||||
|
mStatusLoadingIndicator->setVisible(true);
|
||||||
|
break;
|
||||||
|
case LLFacebookConnect::FB_CONNECTION_FAILED:
|
||||||
|
// Error connecting to the service
|
||||||
|
mStatusErrorText->setVisible(true);
|
||||||
|
status_text = LLTrans::getString("SocialFacebookErrorConnecting");
|
||||||
|
mStatusErrorText->setValue(status_text);
|
||||||
|
break;
|
||||||
|
case LLFacebookConnect::FB_POST_FAILED:
|
||||||
|
// Error posting to the service
|
||||||
|
mStatusErrorText->setVisible(true);
|
||||||
|
status_text = LLTrans::getString("SocialFacebookErrorPosting");
|
||||||
|
mStatusErrorText->setValue(status_text);
|
||||||
|
break;
|
||||||
|
case LLFacebookConnect::FB_DISCONNECTING:
|
||||||
|
// Disconnecting loading indicator
|
||||||
|
mStatusLoadingText->setVisible(true);
|
||||||
|
status_text = LLTrans::getString("SocialFacebookDisconnecting");
|
||||||
|
mStatusLoadingText->setValue(status_text);
|
||||||
|
mStatusLoadingIndicator->setVisible(true);
|
||||||
|
break;
|
||||||
|
case LLFacebookConnect::FB_DISCONNECT_FAILED:
|
||||||
|
// Error disconnecting from the service
|
||||||
|
mStatusErrorText->setVisible(true);
|
||||||
|
status_text = LLTrans::getString("SocialFacebookErrorDisconnecting");
|
||||||
|
mStatusErrorText->setValue(status_text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LLFloater::draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,165 @@
|
||||||
|
/**
|
||||||
|
* @file llfloatersocial.h
|
||||||
|
* @brief Header file for llfloatersocial
|
||||||
|
* @author Gilbert@lindenlab.com
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
|
||||||
|
* Second Life Viewer Source Code
|
||||||
|
* Copyright (C) 2013, Linden Research, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation;
|
||||||
|
* version 2.1 of the License only.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
|
* $/LicenseInfo$
|
||||||
|
*/
|
||||||
|
#ifndef LL_LLFLOATERSOCIAL_H
|
||||||
|
#define LL_LLFLOATERSOCIAL_H
|
||||||
|
|
||||||
|
#include "llfloater.h"
|
||||||
|
#include "lltextbox.h"
|
||||||
|
#include "llviewertexture.h"
|
||||||
|
|
||||||
|
class LLIconCtrl;
|
||||||
|
class LLCheckBoxCtrl;
|
||||||
|
class LLSnapshotLivePreview;
|
||||||
|
|
||||||
|
class LLSocialStatusPanel : public LLPanel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LLSocialStatusPanel();
|
||||||
|
BOOL postBuild();
|
||||||
|
void draw();
|
||||||
|
void onSend();
|
||||||
|
bool onFacebookConnectStateChange(const LLSD& data);
|
||||||
|
|
||||||
|
void sendStatus();
|
||||||
|
void clearAndClose();
|
||||||
|
|
||||||
|
private:
|
||||||
|
LLUICtrl* mMessageTextEditor;
|
||||||
|
LLUICtrl* mPostButton;
|
||||||
|
LLUICtrl* mCancelButton;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LLSocialPhotoPanel : public LLPanel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LLSocialPhotoPanel();
|
||||||
|
~LLSocialPhotoPanel();
|
||||||
|
|
||||||
|
BOOL postBuild();
|
||||||
|
void draw();
|
||||||
|
|
||||||
|
LLSnapshotLivePreview* getPreviewView();
|
||||||
|
void onVisibilityChange(const LLSD& new_visibility);
|
||||||
|
void onClickNewSnapshot();
|
||||||
|
void onSend();
|
||||||
|
bool onFacebookConnectStateChange(const LLSD& data);
|
||||||
|
|
||||||
|
void sendPhoto();
|
||||||
|
void clearAndClose();
|
||||||
|
|
||||||
|
void updateControls();
|
||||||
|
void updateResolution(BOOL do_update);
|
||||||
|
void checkAspectRatio(S32 index);
|
||||||
|
LLUICtrl* getRefreshBtn();
|
||||||
|
|
||||||
|
private:
|
||||||
|
LLHandle<LLView> mPreviewHandle;
|
||||||
|
|
||||||
|
LLUICtrl * mSnapshotPanel;
|
||||||
|
LLUICtrl * mResolutionComboBox;
|
||||||
|
LLUICtrl * mRefreshBtn;
|
||||||
|
LLUICtrl * mWorkingLabel;
|
||||||
|
LLUICtrl * mThumbnailPlaceholder;
|
||||||
|
LLUICtrl * mCaptionTextBox;
|
||||||
|
LLUICtrl * mLocationCheckbox;
|
||||||
|
LLUICtrl * mPostButton;
|
||||||
|
LLUICtrl* mCancelButton;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LLSocialCheckinPanel : public LLPanel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LLSocialCheckinPanel();
|
||||||
|
BOOL postBuild();
|
||||||
|
void draw();
|
||||||
|
void onSend();
|
||||||
|
bool onFacebookConnectStateChange(const LLSD& data);
|
||||||
|
|
||||||
|
void sendCheckin();
|
||||||
|
void clearAndClose();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string mMapUrl;
|
||||||
|
LLPointer<LLViewerFetchedTexture> mMapTexture;
|
||||||
|
LLUICtrl* mPostButton;
|
||||||
|
LLUICtrl* mCancelButton;
|
||||||
|
LLUICtrl* mMessageTextEditor;
|
||||||
|
LLUICtrl* mMapLoadingIndicator;
|
||||||
|
LLIconCtrl* mMapPlaceholder;
|
||||||
|
LLIconCtrl* mMapDefault;
|
||||||
|
LLCheckBoxCtrl* mMapCheckBox;
|
||||||
|
bool mReloadingMapTexture;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LLSocialAccountPanel : public LLPanel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LLSocialAccountPanel();
|
||||||
|
BOOL postBuild();
|
||||||
|
void draw();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onVisibilityChange(const LLSD& new_visibility);
|
||||||
|
bool onFacebookConnectStateChange(const LLSD& data);
|
||||||
|
bool onFacebookConnectInfoChange();
|
||||||
|
void onConnect();
|
||||||
|
void onUseAnotherAccount();
|
||||||
|
void onDisconnect();
|
||||||
|
|
||||||
|
void showConnectButton();
|
||||||
|
void hideConnectButton();
|
||||||
|
void showDisconnectedLayout();
|
||||||
|
void showConnectedLayout();
|
||||||
|
|
||||||
|
LLTextBox * mAccountCaptionLabel;
|
||||||
|
LLTextBox * mAccountNameLabel;
|
||||||
|
LLUICtrl * mPanelButtons;
|
||||||
|
LLUICtrl * mConnectButton;
|
||||||
|
LLUICtrl * mDisconnectButton;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class LLFloaterSocial : public LLFloater
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LLFloaterSocial(const LLSD& key);
|
||||||
|
BOOL postBuild();
|
||||||
|
void draw();
|
||||||
|
void onCancel();
|
||||||
|
|
||||||
|
static void preUpdate();
|
||||||
|
static void postUpdate();
|
||||||
|
|
||||||
|
private:
|
||||||
|
LLSocialPhotoPanel* mSocialPhotoPanel;
|
||||||
|
LLTextBox* mStatusErrorText;
|
||||||
|
LLTextBox* mStatusLoadingText;
|
||||||
|
LLUICtrl* mStatusLoadingIndicator;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LL_LLFLOATERSOCIAL_H
|
||||||
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
#include "llcombobox.h"
|
#include "llcombobox.h"
|
||||||
#include "lliconctrl.h"
|
#include "lliconctrl.h"
|
||||||
#include "llfloaterreg.h"
|
#include "llfloaterreg.h"
|
||||||
|
#include "llfacebookconnect.h"
|
||||||
#include "lllayoutstack.h"
|
#include "lllayoutstack.h"
|
||||||
#include "llpluginclassmedia.h"
|
#include "llpluginclassmedia.h"
|
||||||
#include "llprogressbar.h"
|
#include "llprogressbar.h"
|
||||||
|
|
@ -46,7 +47,8 @@ LLFloaterWebContent::_Params::_Params()
|
||||||
id("id"),
|
id("id"),
|
||||||
window_class("window_class", "web_content"),
|
window_class("window_class", "web_content"),
|
||||||
show_chrome("show_chrome", true),
|
show_chrome("show_chrome", true),
|
||||||
allow_address_entry("allow_address_entry", true),
|
allow_address_entry("allow_address_entry", true),
|
||||||
|
allow_back_forward_navigation("allow_back_forward_navigation", true),
|
||||||
preferred_media_size("preferred_media_size"),
|
preferred_media_size("preferred_media_size"),
|
||||||
trusted_content("trusted_content", false),
|
trusted_content("trusted_content", false),
|
||||||
show_page_title("show_page_title", true)
|
show_page_title("show_page_title", true)
|
||||||
|
|
@ -65,7 +67,11 @@ LLFloaterWebContent::LLFloaterWebContent( const Params& params )
|
||||||
mBtnReload(NULL),
|
mBtnReload(NULL),
|
||||||
mBtnStop(NULL),
|
mBtnStop(NULL),
|
||||||
mUUID(params.id()),
|
mUUID(params.id()),
|
||||||
mShowPageTitle(params.show_page_title)
|
mShowPageTitle(params.show_page_title),
|
||||||
|
mAllowNavigation(true),
|
||||||
|
mCurrentURL(""),
|
||||||
|
mDisplayURL(""),
|
||||||
|
mSecureURL(false)
|
||||||
{
|
{
|
||||||
mCommitCallbackRegistrar.add( "WebContent.Back", boost::bind( &LLFloaterWebContent::onClickBack, this ));
|
mCommitCallbackRegistrar.add( "WebContent.Back", boost::bind( &LLFloaterWebContent::onClickBack, this ));
|
||||||
mCommitCallbackRegistrar.add( "WebContent.Forward", boost::bind( &LLFloaterWebContent::onClickForward, this ));
|
mCommitCallbackRegistrar.add( "WebContent.Forward", boost::bind( &LLFloaterWebContent::onClickForward, this ));
|
||||||
|
|
@ -97,7 +103,7 @@ BOOL LLFloaterWebContent::postBuild()
|
||||||
|
|
||||||
// cache image for secure browsing
|
// cache image for secure browsing
|
||||||
mSecureLockIcon = getChild< LLIconCtrl >("media_secure_lock_flag");
|
mSecureLockIcon = getChild< LLIconCtrl >("media_secure_lock_flag");
|
||||||
|
|
||||||
// initialize the URL history using the system URL History manager
|
// initialize the URL history using the system URL History manager
|
||||||
initializeURLHistory();
|
initializeURLHistory();
|
||||||
|
|
||||||
|
|
@ -243,6 +249,7 @@ void LLFloaterWebContent::open_media(const Params& p)
|
||||||
getChild<LLLayoutPanel>("status_bar")->setVisible(p.show_chrome);
|
getChild<LLLayoutPanel>("status_bar")->setVisible(p.show_chrome);
|
||||||
getChild<LLLayoutPanel>("nav_controls")->setVisible(p.show_chrome);
|
getChild<LLLayoutPanel>("nav_controls")->setVisible(p.show_chrome);
|
||||||
bool address_entry_enabled = p.allow_address_entry && !p.trusted_content;
|
bool address_entry_enabled = p.allow_address_entry && !p.trusted_content;
|
||||||
|
mAllowNavigation = p.allow_back_forward_navigation;
|
||||||
getChildView("address")->setEnabled(address_entry_enabled);
|
getChildView("address")->setEnabled(address_entry_enabled);
|
||||||
getChildView("popexternal")->setEnabled(address_entry_enabled);
|
getChildView("popexternal")->setEnabled(address_entry_enabled);
|
||||||
|
|
||||||
|
|
@ -287,6 +294,16 @@ void LLFloaterWebContent::onOpen(const LLSD& key)
|
||||||
//virtual
|
//virtual
|
||||||
void LLFloaterWebContent::onClose(bool app_quitting)
|
void LLFloaterWebContent::onClose(bool app_quitting)
|
||||||
{
|
{
|
||||||
|
// If we close the web browsing window showing the facebook login, we need to signal to this object that the connection will not happen
|
||||||
|
LLFloater* fbc_web = LLFloaterReg::getInstance("fbc_web");
|
||||||
|
if (fbc_web == this)
|
||||||
|
{
|
||||||
|
if (!LLFacebookConnect::instance().isConnected())
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LLViewerMedia::proxyWindowClosed(mUUID);
|
LLViewerMedia::proxyWindowClosed(mUUID);
|
||||||
destroy();
|
destroy();
|
||||||
}
|
}
|
||||||
|
|
@ -295,8 +312,11 @@ void LLFloaterWebContent::onClose(bool app_quitting)
|
||||||
void LLFloaterWebContent::draw()
|
void LLFloaterWebContent::draw()
|
||||||
{
|
{
|
||||||
// this is asynchronous so we need to keep checking
|
// this is asynchronous so we need to keep checking
|
||||||
mBtnBack->setEnabled( mWebBrowser->canNavigateBack() );
|
mBtnBack->setEnabled( mWebBrowser->canNavigateBack() && mAllowNavigation);
|
||||||
mBtnForward->setEnabled( mWebBrowser->canNavigateForward() );
|
mBtnForward->setEnabled( mWebBrowser->canNavigateForward() && mAllowNavigation);
|
||||||
|
|
||||||
|
// Show/hide the lock icon
|
||||||
|
mSecureLockIcon->setVisible(mSecureURL && !mAddressCombo->hasFocus());
|
||||||
|
|
||||||
LLFloater::draw();
|
LLFloater::draw();
|
||||||
}
|
}
|
||||||
|
|
@ -342,21 +362,8 @@ void LLFloaterWebContent::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent
|
||||||
// we populate the status bar with URLs as they change so clear it now we're done
|
// we populate the status bar with URLs as they change so clear it now we're done
|
||||||
const std::string end_str = "";
|
const std::string end_str = "";
|
||||||
mStatusBarText->setText( end_str );
|
mStatusBarText->setText( end_str );
|
||||||
|
|
||||||
// decide if secure browsing icon should be displayed
|
|
||||||
std::string prefix = std::string("https://");
|
|
||||||
std::string test_prefix = mCurrentURL.substr(0, prefix.length());
|
|
||||||
LLStringUtil::toLower(test_prefix);
|
|
||||||
if(test_prefix == prefix)
|
|
||||||
{
|
|
||||||
mSecureLockIcon->setVisible(true);
|
|
||||||
mAddressCombo->setLeftTextPadding(22);
|
mAddressCombo->setLeftTextPadding(22);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mSecureLockIcon->setVisible(false);
|
|
||||||
mAddressCombo->setLeftTextPadding(2);
|
mAddressCombo->setLeftTextPadding(2);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if(event == MEDIA_EVENT_CLOSE_REQUEST)
|
else if(event == MEDIA_EVENT_CLOSE_REQUEST)
|
||||||
{
|
{
|
||||||
|
|
@ -399,15 +406,40 @@ void LLFloaterWebContent::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent
|
||||||
|
|
||||||
void LLFloaterWebContent::set_current_url(const std::string& url)
|
void LLFloaterWebContent::set_current_url(const std::string& url)
|
||||||
{
|
{
|
||||||
mCurrentURL = url;
|
if (!url.empty())
|
||||||
|
{
|
||||||
|
if (!mCurrentURL.empty())
|
||||||
|
{
|
||||||
|
// Clean up the current browsing list to show true URL
|
||||||
|
mAddressCombo->remove(mDisplayURL);
|
||||||
|
mAddressCombo->add(mCurrentURL);
|
||||||
|
}
|
||||||
|
|
||||||
// serialize url history into the system URL History manager
|
// Update current URL
|
||||||
LLURLHistory::removeURL("browser", mCurrentURL);
|
mCurrentURL = url;
|
||||||
LLURLHistory::addURL("browser", mCurrentURL);
|
LLStringUtil::trim(mCurrentURL);
|
||||||
|
|
||||||
mAddressCombo->remove( mCurrentURL );
|
// Serialize url history into the system URL History manager
|
||||||
mAddressCombo->add( mCurrentURL );
|
LLURLHistory::removeURL("browser", mCurrentURL);
|
||||||
mAddressCombo->selectByValue( mCurrentURL );
|
LLURLHistory::addURL("browser", mCurrentURL);
|
||||||
|
|
||||||
|
// Check if this is a secure URL
|
||||||
|
static const std::string secure_prefix = std::string("https://");
|
||||||
|
std::string prefix = mCurrentURL.substr(0, secure_prefix.length());
|
||||||
|
LLStringUtil::toLower(prefix);
|
||||||
|
mSecureURL = (prefix == secure_prefix);
|
||||||
|
|
||||||
|
// Hack : we move the text a bit to make space for the lock icon in the secure URL case
|
||||||
|
mDisplayURL = (mSecureURL ? " " + mCurrentURL : mCurrentURL);
|
||||||
|
|
||||||
|
// Clean up browsing list (prevent dupes) and add/select the new URL to it
|
||||||
|
mAddressCombo->remove(mCurrentURL);
|
||||||
|
mAddressCombo->add(mDisplayURL);
|
||||||
|
mAddressCombo->selectByValue(mDisplayURL);
|
||||||
|
|
||||||
|
// Set the focus back to the web page. When setting the url, there's no point to leave the focus anywhere else.
|
||||||
|
mWebBrowser->setFocus(TRUE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLFloaterWebContent::onClickForward()
|
void LLFloaterWebContent::onClickForward()
|
||||||
|
|
@ -451,6 +483,7 @@ void LLFloaterWebContent::onEnterAddress()
|
||||||
// make sure there is at least something there.
|
// make sure there is at least something there.
|
||||||
// (perhaps this test should be for minimum length of a URL)
|
// (perhaps this test should be for minimum length of a URL)
|
||||||
std::string url = mAddressCombo->getValue().asString();
|
std::string url = mAddressCombo->getValue().asString();
|
||||||
|
LLStringUtil::trim(url);
|
||||||
if ( url.length() > 0 )
|
if ( url.length() > 0 )
|
||||||
{
|
{
|
||||||
mWebBrowser->navigateTo( url, "text/html");
|
mWebBrowser->navigateTo( url, "text/html");
|
||||||
|
|
@ -462,6 +495,7 @@ void LLFloaterWebContent::onPopExternal()
|
||||||
// make sure there is at least something there.
|
// make sure there is at least something there.
|
||||||
// (perhaps this test should be for minimum length of a URL)
|
// (perhaps this test should be for minimum length of a URL)
|
||||||
std::string url = mAddressCombo->getValue().asString();
|
std::string url = mAddressCombo->getValue().asString();
|
||||||
|
LLStringUtil::trim(url);
|
||||||
if ( url.length() > 0 )
|
if ( url.length() > 0 )
|
||||||
{
|
{
|
||||||
LLWeb::loadURLExternal( url );
|
LLWeb::loadURLExternal( url );
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ public:
|
||||||
id;
|
id;
|
||||||
Optional<bool> show_chrome,
|
Optional<bool> show_chrome,
|
||||||
allow_address_entry,
|
allow_address_entry,
|
||||||
|
allow_back_forward_navigation,
|
||||||
trusted_content,
|
trusted_content,
|
||||||
show_page_title;
|
show_page_title;
|
||||||
Optional<LLRect> preferred_media_size;
|
Optional<LLRect> preferred_media_size;
|
||||||
|
|
@ -106,9 +107,12 @@ protected:
|
||||||
LLView* mBtnReload;
|
LLView* mBtnReload;
|
||||||
LLView* mBtnStop;
|
LLView* mBtnStop;
|
||||||
|
|
||||||
std::string mCurrentURL;
|
std::string mCurrentURL; // Current URL
|
||||||
|
std::string mDisplayURL; // URL being displayed in the address bar (can differ by trailing / leading space)
|
||||||
std::string mUUID;
|
std::string mUUID;
|
||||||
bool mShowPageTitle;
|
bool mShowPageTitle;
|
||||||
|
bool mAllowNavigation;
|
||||||
|
bool mSecureURL; // true when the current url is prefixed "https://"
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LL_LLFLOATERWEBCONTENT_H
|
#endif // LL_LLFLOATERWEBCONTENT_H
|
||||||
|
|
|
||||||
|
|
@ -130,10 +130,10 @@ void process_dnd_im(const LLSD& notification)
|
||||||
fromID,
|
fromID,
|
||||||
false,
|
false,
|
||||||
false); //will need slight refactor to retrieve whether offline message or not (assume online for now)
|
false); //will need slight refactor to retrieve whether offline message or not (assume online for now)
|
||||||
}
|
}
|
||||||
|
|
||||||
notify_of_message(data, true);
|
notify_of_message(data, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -155,22 +155,22 @@ static void on_avatar_name_cache_toast(const LLUUID& agent_id,
|
||||||
|
|
||||||
void notify_of_message(const LLSD& msg, bool is_dnd_msg)
|
void notify_of_message(const LLSD& msg, bool is_dnd_msg)
|
||||||
{
|
{
|
||||||
std::string user_preferences;
|
std::string user_preferences;
|
||||||
LLUUID participant_id = msg[is_dnd_msg ? "FROM_ID" : "from_id"].asUUID();
|
LLUUID participant_id = msg[is_dnd_msg ? "FROM_ID" : "from_id"].asUUID();
|
||||||
LLUUID session_id = msg[is_dnd_msg ? "SESSION_ID" : "session_id"].asUUID();
|
LLUUID session_id = msg[is_dnd_msg ? "SESSION_ID" : "session_id"].asUUID();
|
||||||
LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id);
|
LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id);
|
||||||
|
|
||||||
// do not show notification which goes from agent
|
// do not show notification which goes from agent
|
||||||
if (gAgent.getID() == participant_id)
|
if (gAgent.getID() == participant_id)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine state of conversations floater
|
// determine state of conversations floater
|
||||||
enum {CLOSED, NOT_ON_TOP, ON_TOP, ON_TOP_AND_ITEM_IS_SELECTED} conversations_floater_status;
|
enum {CLOSED, NOT_ON_TOP, ON_TOP, ON_TOP_AND_ITEM_IS_SELECTED} conversations_floater_status;
|
||||||
|
|
||||||
|
|
||||||
LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
|
LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
|
||||||
LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(session_id);
|
LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(session_id);
|
||||||
bool store_dnd_message = false; // flag storage of a dnd message
|
bool store_dnd_message = false; // flag storage of a dnd message
|
||||||
bool is_session_focused = session_floater->isTornOff() && session_floater->hasFocus();
|
bool is_session_focused = session_floater->isTornOff() && session_floater->hasFocus();
|
||||||
|
|
@ -179,23 +179,23 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)
|
||||||
conversations_floater_status = CLOSED;
|
conversations_floater_status = CLOSED;
|
||||||
}
|
}
|
||||||
else if (!im_box->hasFocus() &&
|
else if (!im_box->hasFocus() &&
|
||||||
!(session_floater && LLFloater::isVisible(session_floater)
|
!(session_floater && LLFloater::isVisible(session_floater)
|
||||||
&& !session_floater->isMinimized() && session_floater->hasFocus()))
|
&& !session_floater->isMinimized() && session_floater->hasFocus()))
|
||||||
{
|
{
|
||||||
conversations_floater_status = NOT_ON_TOP;
|
conversations_floater_status = NOT_ON_TOP;
|
||||||
}
|
}
|
||||||
else if (im_box->getSelectedSession() != session_id)
|
else if (im_box->getSelectedSession() != session_id)
|
||||||
{
|
{
|
||||||
conversations_floater_status = ON_TOP;
|
conversations_floater_status = ON_TOP;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
conversations_floater_status = ON_TOP_AND_ITEM_IS_SELECTED;
|
conversations_floater_status = ON_TOP_AND_ITEM_IS_SELECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine user prefs for this session
|
// determine user prefs for this session
|
||||||
if (session_id.isNull())
|
if (session_id.isNull())
|
||||||
{
|
{
|
||||||
if (msg["source_type"].asInteger() == CHAT_SOURCE_OBJECT)
|
if (msg["source_type"].asInteger() == CHAT_SOURCE_OBJECT)
|
||||||
{
|
{
|
||||||
user_preferences = gSavedSettings.getString("NotificationObjectIMOptions");
|
user_preferences = gSavedSettings.getString("NotificationObjectIMOptions");
|
||||||
|
|
@ -206,50 +206,50 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
user_preferences = gSavedSettings.getString("NotificationNearbyChatOptions");
|
user_preferences = gSavedSettings.getString("NotificationNearbyChatOptions");
|
||||||
if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNearbyChatIM") == TRUE))
|
if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNearbyChatIM") == TRUE))
|
||||||
{
|
{
|
||||||
make_ui_sound("UISndNewIncomingIMSession");
|
make_ui_sound("UISndNewIncomingIMSession");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(session->isP2PSessionType())
|
else if(session->isP2PSessionType())
|
||||||
{
|
{
|
||||||
if (LLAvatarTracker::instance().isBuddy(participant_id))
|
if (LLAvatarTracker::instance().isBuddy(participant_id))
|
||||||
{
|
{
|
||||||
user_preferences = gSavedSettings.getString("NotificationFriendIMOptions");
|
user_preferences = gSavedSettings.getString("NotificationFriendIMOptions");
|
||||||
if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundFriendIM") == TRUE))
|
if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundFriendIM") == TRUE))
|
||||||
{
|
{
|
||||||
make_ui_sound("UISndNewIncomingIMSession");
|
make_ui_sound("UISndNewIncomingIMSession");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
user_preferences = gSavedSettings.getString("NotificationNonFriendIMOptions");
|
user_preferences = gSavedSettings.getString("NotificationNonFriendIMOptions");
|
||||||
if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNonFriendIM") == TRUE))
|
if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNonFriendIM") == TRUE))
|
||||||
{
|
{
|
||||||
make_ui_sound("UISndNewIncomingIMSession");
|
make_ui_sound("UISndNewIncomingIMSession");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(session->isAdHocSessionType())
|
else if(session->isAdHocSessionType())
|
||||||
{
|
{
|
||||||
user_preferences = gSavedSettings.getString("NotificationConferenceIMOptions");
|
user_preferences = gSavedSettings.getString("NotificationConferenceIMOptions");
|
||||||
if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundConferenceIM") == TRUE))
|
if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundConferenceIM") == TRUE))
|
||||||
{
|
{
|
||||||
make_ui_sound("UISndNewIncomingIMSession");
|
make_ui_sound("UISndNewIncomingIMSession");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(session->isGroupSessionType())
|
else if(session->isGroupSessionType())
|
||||||
{
|
{
|
||||||
user_preferences = gSavedSettings.getString("NotificationGroupChatOptions");
|
user_preferences = gSavedSettings.getString("NotificationGroupChatOptions");
|
||||||
if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundGroupChatIM") == TRUE))
|
if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundGroupChatIM") == TRUE))
|
||||||
{
|
{
|
||||||
make_ui_sound("UISndNewIncomingIMSession");
|
make_ui_sound("UISndNewIncomingIMSession");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// actions:
|
// actions:
|
||||||
|
|
||||||
// 0. nothing - exit
|
// 0. nothing - exit
|
||||||
if (("noaction" == user_preferences ||
|
if (("noaction" == user_preferences ||
|
||||||
|
|
@ -287,23 +287,23 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
store_dnd_message = true;
|
store_dnd_message = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Flash line item
|
// 2. Flash line item
|
||||||
if ("openconversations" == user_preferences
|
if ("openconversations" == user_preferences
|
||||||
|| ON_TOP == conversations_floater_status
|
|| ON_TOP == conversations_floater_status
|
||||||
|| ("toast" == user_preferences && ON_TOP != conversations_floater_status)
|
|| ("toast" == user_preferences && ON_TOP != conversations_floater_status)
|
||||||
|| ("flash" == user_preferences && (CLOSED == conversations_floater_status
|
|| ("flash" == user_preferences && (CLOSED == conversations_floater_status
|
||||||
|| NOT_ON_TOP == conversations_floater_status))
|
|| NOT_ON_TOP == conversations_floater_status))
|
||||||
|| is_dnd_msg)
|
|| is_dnd_msg)
|
||||||
{
|
{
|
||||||
if(!LLMuteList::getInstance()->isMuted(participant_id))
|
if(!LLMuteList::getInstance()->isMuted(participant_id))
|
||||||
{
|
{
|
||||||
if(gAgent.isDoNotDisturb())
|
if(gAgent.isDoNotDisturb())
|
||||||
{
|
{
|
||||||
store_dnd_message = true;
|
store_dnd_message = true;
|
||||||
|
|
@ -318,43 +318,43 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
im_box->flashConversationItemWidget(session_id, true);
|
im_box->flashConversationItemWidget(session_id, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Flash FUI button
|
// 3. Flash FUI button
|
||||||
if (("toast" == user_preferences || "flash" == user_preferences) &&
|
if (("toast" == user_preferences || "flash" == user_preferences) &&
|
||||||
(CLOSED == conversations_floater_status
|
(CLOSED == conversations_floater_status
|
||||||
|| NOT_ON_TOP == conversations_floater_status)
|
|| NOT_ON_TOP == conversations_floater_status)
|
||||||
&& !is_session_focused
|
&& !is_session_focused
|
||||||
&& !is_dnd_msg) //prevent flashing FUI button because the conversation floater will have already opened
|
&& !is_dnd_msg) //prevent flashing FUI button because the conversation floater will have already opened
|
||||||
{
|
{
|
||||||
if(!LLMuteList::getInstance()->isMuted(participant_id))
|
if(!LLMuteList::getInstance()->isMuted(participant_id))
|
||||||
{
|
{
|
||||||
if(!gAgent.isDoNotDisturb())
|
if(!gAgent.isDoNotDisturb())
|
||||||
{
|
{
|
||||||
gToolBarView->flashCommand(LLCommandId("chat"), true, im_box->isMinimized());
|
gToolBarView->flashCommand(LLCommandId("chat"), true, im_box->isMinimized());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
store_dnd_message = true;
|
store_dnd_message = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Toast
|
// 4. Toast
|
||||||
if ((("toast" == user_preferences) &&
|
if ((("toast" == user_preferences) &&
|
||||||
(ON_TOP_AND_ITEM_IS_SELECTED != conversations_floater_status) &&
|
(ON_TOP_AND_ITEM_IS_SELECTED != conversations_floater_status) &&
|
||||||
(!session_floater->isTornOff() || !LLFloater::isVisible(session_floater)))
|
(!session_floater->isTornOff() || !LLFloater::isVisible(session_floater)))
|
||||||
|| !session_floater->isMessagePaneExpanded())
|
|| !session_floater->isMessagePaneExpanded())
|
||||||
|
|
||||||
{
|
{
|
||||||
//Show IM toasts (upper right toasts)
|
//Show IM toasts (upper right toasts)
|
||||||
// Skip toasting for system messages and for nearby chat
|
// Skip toasting for system messages and for nearby chat
|
||||||
if(session_id.notNull() && participant_id.notNull())
|
if(session_id.notNull() && participant_id.notNull())
|
||||||
{
|
{
|
||||||
if(!is_dnd_msg)
|
if(!is_dnd_msg)
|
||||||
{
|
{
|
||||||
if(gAgent.isDoNotDisturb())
|
if(gAgent.isDoNotDisturb())
|
||||||
|
|
@ -363,10 +363,10 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg));
|
LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (store_dnd_message)
|
if (store_dnd_message)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -4739,6 +4739,16 @@ void LLCallingCardBridge::performAction(LLInventoryModel* model, std::string act
|
||||||
LLAvatarActions::offerTeleport(item->getCreatorUUID());
|
LLAvatarActions::offerTeleport(item->getCreatorUUID());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if ("request_lure" == action)
|
||||||
|
{
|
||||||
|
LLViewerInventoryItem *item = getItem();
|
||||||
|
if (item && (item->getCreatorUUID() != gAgent.getID()) &&
|
||||||
|
(!item->getCreatorUUID().isNull()))
|
||||||
|
{
|
||||||
|
LLAvatarActions::teleportRequest(item->getCreatorUUID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else LLItemBridge::performAction(model, action);
|
else LLItemBridge::performAction(model, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4825,6 +4835,7 @@ void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
|
||||||
items.push_back(std::string("Send Instant Message Separator"));
|
items.push_back(std::string("Send Instant Message Separator"));
|
||||||
items.push_back(std::string("Send Instant Message"));
|
items.push_back(std::string("Send Instant Message"));
|
||||||
items.push_back(std::string("Offer Teleport..."));
|
items.push_back(std::string("Offer Teleport..."));
|
||||||
|
items.push_back(std::string("Request Teleport..."));
|
||||||
items.push_back(std::string("Conference Chat"));
|
items.push_back(std::string("Conference Chat"));
|
||||||
|
|
||||||
if (!good_card)
|
if (!good_card)
|
||||||
|
|
@ -4834,6 +4845,7 @@ void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
|
||||||
if (!good_card || !user_online)
|
if (!good_card || !user_online)
|
||||||
{
|
{
|
||||||
disabled_items.push_back(std::string("Offer Teleport..."));
|
disabled_items.push_back(std::string("Offer Teleport..."));
|
||||||
|
disabled_items.push_back(std::string("Request Teleport..."));
|
||||||
disabled_items.push_back(std::string("Conference Chat"));
|
disabled_items.push_back(std::string("Conference Chat"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -343,8 +343,11 @@ void LLNetMap::draw()
|
||||||
// Draw avatars
|
// Draw avatars
|
||||||
for (U32 i = 0; i < avatar_ids.size(); i++)
|
for (U32 i = 0; i < avatar_ids.size(); i++)
|
||||||
{
|
{
|
||||||
pos_map = globalPosToView(positions[i]);
|
|
||||||
LLUUID uuid = avatar_ids[i];
|
LLUUID uuid = avatar_ids[i];
|
||||||
|
// Skip self, we'll draw it later
|
||||||
|
if (uuid == gAgent.getID()) continue;
|
||||||
|
|
||||||
|
pos_map = globalPosToView(positions[i]);
|
||||||
|
|
||||||
bool show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(uuid) != NULL);
|
bool show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(uuid) != NULL);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,9 @@
|
||||||
#include "llnotificationmanager.h"
|
#include "llnotificationmanager.h"
|
||||||
#include "llnotifications.h"
|
#include "llnotifications.h"
|
||||||
#include "llscriptfloater.h"
|
#include "llscriptfloater.h"
|
||||||
|
#include "llfacebookconnect.h"
|
||||||
|
#include "llavatarname.h"
|
||||||
|
#include "llavatarnamecache.h"
|
||||||
|
|
||||||
using namespace LLNotificationsUI;
|
using namespace LLNotificationsUI;
|
||||||
|
|
||||||
|
|
@ -87,7 +90,7 @@ bool LLScriptHandler::processNotification(const LLNotificationPtr& notification)
|
||||||
{
|
{
|
||||||
LLScriptFloaterManager::getInstance()->onAddNotification(notification->getID());
|
LLScriptFloaterManager::getInstance()->onAddNotification(notification->getID());
|
||||||
}
|
}
|
||||||
else
|
else if (notification->canShowToast())
|
||||||
{
|
{
|
||||||
LLToastPanel* notify_box = LLToastPanel::buidPanelFromNotification(notification);
|
LLToastPanel* notify_box = LLToastPanel::buidPanelFromNotification(notification);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@
|
||||||
|
|
||||||
// libs
|
// libs
|
||||||
#include "llavatarname.h"
|
#include "llavatarname.h"
|
||||||
|
#include "llconversationview.h"
|
||||||
|
#include "llfloaterimcontainer.h"
|
||||||
#include "llfloaterreg.h"
|
#include "llfloaterreg.h"
|
||||||
#include "llfloatersidepanelcontainer.h"
|
#include "llfloatersidepanelcontainer.h"
|
||||||
#include "llmenubutton.h"
|
#include "llmenubutton.h"
|
||||||
|
|
@ -48,15 +50,19 @@
|
||||||
#include "llavataractions.h"
|
#include "llavataractions.h"
|
||||||
#include "llavatarlist.h"
|
#include "llavatarlist.h"
|
||||||
#include "llavatarlistitem.h"
|
#include "llavatarlistitem.h"
|
||||||
|
#include "llavatarnamecache.h"
|
||||||
#include "llcallingcard.h" // for LLAvatarTracker
|
#include "llcallingcard.h" // for LLAvatarTracker
|
||||||
|
#include "llcallbacklist.h"
|
||||||
|
#include "llerror.h"
|
||||||
|
#include "llfacebookconnect.h"
|
||||||
#include "llfloateravatarpicker.h"
|
#include "llfloateravatarpicker.h"
|
||||||
//#include "llfloaterminiinspector.h"
|
|
||||||
#include "llfriendcard.h"
|
#include "llfriendcard.h"
|
||||||
#include "llgroupactions.h"
|
#include "llgroupactions.h"
|
||||||
#include "llgrouplist.h"
|
#include "llgrouplist.h"
|
||||||
#include "llinventoryobserver.h"
|
#include "llinventoryobserver.h"
|
||||||
#include "llnetmap.h"
|
#include "llnetmap.h"
|
||||||
#include "llpanelpeoplemenus.h"
|
#include "llpanelpeoplemenus.h"
|
||||||
|
#include "llparticipantlist.h"
|
||||||
#include "llsidetraypanelcontainer.h"
|
#include "llsidetraypanelcontainer.h"
|
||||||
#include "llrecentpeople.h"
|
#include "llrecentpeople.h"
|
||||||
#include "llviewercontrol.h" // for gSavedSettings
|
#include "llviewercontrol.h" // for gSavedSettings
|
||||||
|
|
@ -64,6 +70,10 @@
|
||||||
#include "llvoiceclient.h"
|
#include "llvoiceclient.h"
|
||||||
#include "llworld.h"
|
#include "llworld.h"
|
||||||
#include "llspeakers.h"
|
#include "llspeakers.h"
|
||||||
|
#include "llfloaterwebcontent.h"
|
||||||
|
|
||||||
|
#include "llagentui.h"
|
||||||
|
#include "llslurl.h"
|
||||||
|
|
||||||
#define FRIEND_LIST_UPDATE_TIMEOUT 0.5
|
#define FRIEND_LIST_UPDATE_TIMEOUT 0.5
|
||||||
#define NEARBY_LIST_UPDATE_INTERVAL 1
|
#define NEARBY_LIST_UPDATE_INTERVAL 1
|
||||||
|
|
@ -73,9 +83,9 @@ static const std::string FRIENDS_TAB_NAME = "friends_panel";
|
||||||
static const std::string GROUP_TAB_NAME = "groups_panel";
|
static const std::string GROUP_TAB_NAME = "groups_panel";
|
||||||
static const std::string RECENT_TAB_NAME = "recent_panel";
|
static const std::string RECENT_TAB_NAME = "recent_panel";
|
||||||
static const std::string BLOCKED_TAB_NAME = "blocked_panel"; // blocked avatars
|
static const std::string BLOCKED_TAB_NAME = "blocked_panel"; // blocked avatars
|
||||||
|
|
||||||
static const std::string COLLAPSED_BY_USER = "collapsed_by_user";
|
static const std::string COLLAPSED_BY_USER = "collapsed_by_user";
|
||||||
|
|
||||||
|
|
||||||
extern S32 gMaxAgentGroups;
|
extern S32 gMaxAgentGroups;
|
||||||
|
|
||||||
/** Comparator for comparing avatar items by last interaction date */
|
/** Comparator for comparing avatar items by last interaction date */
|
||||||
|
|
@ -495,6 +505,7 @@ public:
|
||||||
|
|
||||||
LLPanelPeople::LLPanelPeople()
|
LLPanelPeople::LLPanelPeople()
|
||||||
: LLPanel(),
|
: LLPanel(),
|
||||||
|
mTryToConnectToFbc(true),
|
||||||
mTabContainer(NULL),
|
mTabContainer(NULL),
|
||||||
mOnlineFriendList(NULL),
|
mOnlineFriendList(NULL),
|
||||||
mAllFriendList(NULL),
|
mAllFriendList(NULL),
|
||||||
|
|
@ -573,6 +584,7 @@ BOOL LLPanelPeople::postBuild()
|
||||||
getChild<LLFilterEditor>("friends_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
|
getChild<LLFilterEditor>("friends_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
|
||||||
getChild<LLFilterEditor>("groups_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
|
getChild<LLFilterEditor>("groups_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
|
||||||
getChild<LLFilterEditor>("recent_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
|
getChild<LLFilterEditor>("recent_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
|
||||||
|
getChild<LLFilterEditor>("fbc_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
|
||||||
|
|
||||||
mTabContainer = getChild<LLTabContainer>("tabs");
|
mTabContainer = getChild<LLTabContainer>("tabs");
|
||||||
mTabContainer->setCommitCallback(boost::bind(&LLPanelPeople::onTabSelected, this, _2));
|
mTabContainer->setCommitCallback(boost::bind(&LLPanelPeople::onTabSelected, this, _2));
|
||||||
|
|
@ -583,8 +595,11 @@ BOOL LLPanelPeople::postBuild()
|
||||||
// updater is active only if panel is visible to user.
|
// updater is active only if panel is visible to user.
|
||||||
friends_tab->setVisibleCallback(boost::bind(&Updater::setActive, mFriendListUpdater, _2));
|
friends_tab->setVisibleCallback(boost::bind(&Updater::setActive, mFriendListUpdater, _2));
|
||||||
friends_tab->setVisibleCallback(boost::bind(&LLPanelPeople::removePicker, this));
|
friends_tab->setVisibleCallback(boost::bind(&LLPanelPeople::removePicker, this));
|
||||||
|
friends_tab->setVisibleCallback(boost::bind(&LLPanelPeople::updateFacebookList, this, _2));
|
||||||
|
|
||||||
mOnlineFriendList = friends_tab->getChild<LLAvatarList>("avatars_online");
|
mOnlineFriendList = friends_tab->getChild<LLAvatarList>("avatars_online");
|
||||||
mAllFriendList = friends_tab->getChild<LLAvatarList>("avatars_all");
|
mAllFriendList = friends_tab->getChild<LLAvatarList>("avatars_all");
|
||||||
|
mSuggestedFriends = friends_tab->getChild<LLAvatarList>("suggested_friends");
|
||||||
mOnlineFriendList->setNoItemsCommentText(getString("no_friends_online"));
|
mOnlineFriendList->setNoItemsCommentText(getString("no_friends_online"));
|
||||||
mOnlineFriendList->setShowIcons("FriendsListShowIcons");
|
mOnlineFriendList->setShowIcons("FriendsListShowIcons");
|
||||||
mOnlineFriendList->showPermissions("FriendsListShowPermissions");
|
mOnlineFriendList->showPermissions("FriendsListShowPermissions");
|
||||||
|
|
@ -617,6 +632,7 @@ BOOL LLPanelPeople::postBuild()
|
||||||
mRecentList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu);
|
mRecentList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu);
|
||||||
mAllFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu);
|
mAllFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu);
|
||||||
mOnlineFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu);
|
mOnlineFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu);
|
||||||
|
mSuggestedFriends->setContextMenu(&LLPanelPeopleMenus::gSuggestedFriendsContextMenu);
|
||||||
|
|
||||||
setSortOrder(mRecentList, (ESortOrder)gSavedSettings.getU32("RecentPeopleSortOrder"), false);
|
setSortOrder(mRecentList, (ESortOrder)gSavedSettings.getU32("RecentPeopleSortOrder"), false);
|
||||||
setSortOrder(mAllFriendList, (ESortOrder)gSavedSettings.getU32("FriendsSortOrder"), false);
|
setSortOrder(mAllFriendList, (ESortOrder)gSavedSettings.getU32("FriendsSortOrder"), false);
|
||||||
|
|
@ -695,7 +711,7 @@ void LLPanelPeople::updateFriendListHelpText()
|
||||||
|
|
||||||
// Seems sometimes all_friends can be empty because of issue with Inventory loading (clear cache, slow connection...)
|
// Seems sometimes all_friends can be empty because of issue with Inventory loading (clear cache, slow connection...)
|
||||||
// So, lets check all lists to avoid overlapping the text with online list. See EXT-6448.
|
// So, lets check all lists to avoid overlapping the text with online list. See EXT-6448.
|
||||||
bool any_friend_exists = mAllFriendList->filterHasMatches() || mOnlineFriendList->filterHasMatches();
|
bool any_friend_exists = mAllFriendList->filterHasMatches() || mOnlineFriendList->filterHasMatches() || mSuggestedFriends->filterHasMatches();
|
||||||
no_friends_text->setVisible(!any_friend_exists);
|
no_friends_text->setVisible(!any_friend_exists);
|
||||||
if (no_friends_text->getVisible())
|
if (no_friends_text->getVisible())
|
||||||
{
|
{
|
||||||
|
|
@ -762,9 +778,40 @@ void LLPanelPeople::updateFriendList()
|
||||||
mAllFriendList->setDirty(true, !mAllFriendList->filterHasMatches());
|
mAllFriendList->setDirty(true, !mAllFriendList->filterHasMatches());
|
||||||
//update trash and other buttons according to a selected item
|
//update trash and other buttons according to a selected item
|
||||||
updateButtons();
|
updateButtons();
|
||||||
|
updateSuggestedFriendList();
|
||||||
showFriendsAccordionsIfNeeded();
|
showFriendsAccordionsIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LLPanelPeople::updateSuggestedFriendList()
|
||||||
|
{
|
||||||
|
const LLAvatarTracker& av_tracker = LLAvatarTracker::instance();
|
||||||
|
uuid_vec_t& suggested_friends = mSuggestedFriends->getIDs();
|
||||||
|
suggested_friends.clear();
|
||||||
|
|
||||||
|
//Add suggested friends
|
||||||
|
LLSD friends = LLFacebookConnect::instance().getContent();
|
||||||
|
for (LLSD::array_const_iterator i = friends.beginArray(); i != friends.endArray(); ++i)
|
||||||
|
{
|
||||||
|
LLUUID agent_id = (*i).asUUID();
|
||||||
|
bool second_life_buddy = agent_id.notNull() ? av_tracker.isBuddy(agent_id) : false;
|
||||||
|
|
||||||
|
if(!second_life_buddy)
|
||||||
|
{
|
||||||
|
//FB+SL but not SL friend
|
||||||
|
if (agent_id.notNull())
|
||||||
|
{
|
||||||
|
suggested_friends.push_back(agent_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Force a refresh when there aren't any filter matches (prevent displaying content that shouldn't display)
|
||||||
|
mSuggestedFriends->setDirty(true, !mSuggestedFriends->filterHasMatches());
|
||||||
|
showFriendsAccordionsIfNeeded();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void LLPanelPeople::updateNearbyList()
|
void LLPanelPeople::updateNearbyList()
|
||||||
{
|
{
|
||||||
if (!mNearbyList)
|
if (!mNearbyList)
|
||||||
|
|
@ -788,6 +835,51 @@ void LLPanelPeople::updateRecentList()
|
||||||
mRecentList->setDirty();
|
mRecentList->setDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LLPanelPeople::onConnectedToFacebook(const LLSD& data)
|
||||||
|
{
|
||||||
|
LLSD::Integer connection_state = data.get("enum").asInteger();
|
||||||
|
|
||||||
|
if (connection_state == LLFacebookConnect::FB_CONNECTED)
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().loadFacebookFriends();
|
||||||
|
}
|
||||||
|
else if(connection_state == LLFacebookConnect::FB_NOT_CONNECTED)
|
||||||
|
{
|
||||||
|
updateSuggestedFriendList();
|
||||||
|
};
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLPanelPeople::updateFacebookList(bool visible)
|
||||||
|
{
|
||||||
|
if (visible)
|
||||||
|
{
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectContent").stopListening("LLPanelPeople"); // just in case it is already listening
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectContent").listen("LLPanelPeople", boost::bind(&LLPanelPeople::updateSuggestedFriendList, this));
|
||||||
|
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLPanelPeople"); // just in case it is already listening
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectState").listen("LLPanelPeople", boost::bind(&LLPanelPeople::onConnectedToFacebook, this, _1));
|
||||||
|
|
||||||
|
if (LLFacebookConnect::instance().isConnected())
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().loadFacebookFriends();
|
||||||
|
}
|
||||||
|
else if(mTryToConnectToFbc)
|
||||||
|
{
|
||||||
|
LLFacebookConnect::instance().checkConnectionToFacebook();
|
||||||
|
mTryToConnectToFbc = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSuggestedFriendList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectState").stopListening("LLPanelPeople");
|
||||||
|
LLEventPumps::instance().obtain("FacebookConnectContent").stopListening("LLPanelPeople");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LLPanelPeople::updateButtons()
|
void LLPanelPeople::updateButtons()
|
||||||
{
|
{
|
||||||
std::string cur_tab = getActiveTabName();
|
std::string cur_tab = getActiveTabName();
|
||||||
|
|
@ -993,23 +1085,25 @@ void LLPanelPeople::onFilterEdit(const std::string& search_string)
|
||||||
{
|
{
|
||||||
// store accordion tabs opened/closed state before any manipulation with accordion tabs
|
// store accordion tabs opened/closed state before any manipulation with accordion tabs
|
||||||
if (!saved_filter.empty())
|
if (!saved_filter.empty())
|
||||||
{
|
{
|
||||||
notifyChildren(LLSD().with("action","store_state"));
|
notifyChildren(LLSD().with("action","store_state"));
|
||||||
}
|
}
|
||||||
|
|
||||||
mOnlineFriendList->setNameFilter(filter);
|
mOnlineFriendList->setNameFilter(filter);
|
||||||
mAllFriendList->setNameFilter(filter);
|
mAllFriendList->setNameFilter(filter);
|
||||||
|
mSuggestedFriends->setNameFilter(filter);
|
||||||
|
|
||||||
setAccordionCollapsedByUser("tab_online", false);
|
setAccordionCollapsedByUser("tab_online", false);
|
||||||
setAccordionCollapsedByUser("tab_all", false);
|
setAccordionCollapsedByUser("tab_all", false);
|
||||||
showFriendsAccordionsIfNeeded();
|
setAccordionCollapsedByUser("tab_suggested_friends", false);
|
||||||
|
showFriendsAccordionsIfNeeded();
|
||||||
|
|
||||||
// restore accordion tabs state _after_ all manipulations
|
// restore accordion tabs state _after_ all manipulations
|
||||||
if(saved_filter.empty())
|
if(saved_filter.empty())
|
||||||
{
|
{
|
||||||
notifyChildren(LLSD().with("action","restore_state"));
|
notifyChildren(LLSD().with("action","restore_state"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (cur_tab == GROUP_TAB_NAME)
|
else if (cur_tab == GROUP_TAB_NAME)
|
||||||
{
|
{
|
||||||
mGroupList->setNameFilter(filter);
|
mGroupList->setNameFilter(filter);
|
||||||
|
|
@ -1229,7 +1323,7 @@ void LLPanelPeople::onFriendsViewSortMenuItemClicked(const LLSD& userdata)
|
||||||
mAllFriendList->showPermissions(show_permissions);
|
mAllFriendList->showPermissions(show_permissions);
|
||||||
mOnlineFriendList->showPermissions(show_permissions);
|
mOnlineFriendList->showPermissions(show_permissions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLPanelPeople::onGroupsViewSortMenuItemClicked(const LLSD& userdata)
|
void LLPanelPeople::onGroupsViewSortMenuItemClicked(const LLSD& userdata)
|
||||||
{
|
{
|
||||||
|
|
@ -1387,6 +1481,7 @@ void LLPanelPeople::showFriendsAccordionsIfNeeded()
|
||||||
// Expand and show accordions if needed, else - hide them
|
// Expand and show accordions if needed, else - hide them
|
||||||
showAccordion("tab_online", mOnlineFriendList->filterHasMatches());
|
showAccordion("tab_online", mOnlineFriendList->filterHasMatches());
|
||||||
showAccordion("tab_all", mAllFriendList->filterHasMatches());
|
showAccordion("tab_all", mAllFriendList->filterHasMatches());
|
||||||
|
showAccordion("tab_suggested_friends", mSuggestedFriends->filterHasMatches());
|
||||||
|
|
||||||
// Rearrange accordions
|
// Rearrange accordions
|
||||||
LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("friends_accordion");
|
LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("friends_accordion");
|
||||||
|
|
@ -1450,4 +1545,5 @@ bool LLPanelPeople::isAccordionCollapsedByUser(const std::string& name)
|
||||||
return isAccordionCollapsedByUser(getChild<LLUICtrl>(name));
|
return isAccordionCollapsedByUser(getChild<LLUICtrl>(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// EOF
|
// EOF
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
*
|
*
|
||||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
* $/LicenseInfo$
|
* $/LicenseInfo$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef LL_LLPANELPEOPLE_H
|
#ifndef LL_LLPANELPEOPLE_H
|
||||||
#define LL_LLPANELPEOPLE_H
|
#define LL_LLPANELPEOPLE_H
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
#include <llpanel.h>
|
#include <llpanel.h>
|
||||||
|
|
||||||
#include "llcallingcard.h" // for avatar tracker
|
#include "llcallingcard.h" // for avatar tracker
|
||||||
|
#include "llfloaterwebcontent.h"
|
||||||
#include "llvoiceclient.h"
|
#include "llvoiceclient.h"
|
||||||
|
|
||||||
class LLAvatarList;
|
class LLAvatarList;
|
||||||
|
|
@ -55,6 +56,8 @@ public:
|
||||||
// when voice is available
|
// when voice is available
|
||||||
/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
|
/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
|
||||||
|
|
||||||
|
bool mTryToConnectToFbc;
|
||||||
|
|
||||||
// internals
|
// internals
|
||||||
class Updater;
|
class Updater;
|
||||||
|
|
||||||
|
|
@ -73,8 +76,10 @@ private:
|
||||||
// methods indirectly called by the updaters
|
// methods indirectly called by the updaters
|
||||||
void updateFriendListHelpText();
|
void updateFriendListHelpText();
|
||||||
void updateFriendList();
|
void updateFriendList();
|
||||||
|
bool updateSuggestedFriendList();
|
||||||
void updateNearbyList();
|
void updateNearbyList();
|
||||||
void updateRecentList();
|
void updateRecentList();
|
||||||
|
void updateFacebookList(bool visible);
|
||||||
|
|
||||||
bool isItemsFreeOfFriends(const uuid_vec_t& uuids);
|
bool isItemsFreeOfFriends(const uuid_vec_t& uuids);
|
||||||
|
|
||||||
|
|
@ -121,6 +126,8 @@ private:
|
||||||
|
|
||||||
void onFriendListRefreshComplete(LLUICtrl*ctrl, const LLSD& param);
|
void onFriendListRefreshComplete(LLUICtrl*ctrl, const LLSD& param);
|
||||||
|
|
||||||
|
bool onConnectedToFacebook(const LLSD& data);
|
||||||
|
|
||||||
void setAccordionCollapsedByUser(LLUICtrl* acc_tab, bool collapsed);
|
void setAccordionCollapsedByUser(LLUICtrl* acc_tab, bool collapsed);
|
||||||
void setAccordionCollapsedByUser(const std::string& name, bool collapsed);
|
void setAccordionCollapsedByUser(const std::string& name, bool collapsed);
|
||||||
bool isAccordionCollapsedByUser(LLUICtrl* acc_tab);
|
bool isAccordionCollapsedByUser(LLUICtrl* acc_tab);
|
||||||
|
|
@ -129,6 +136,7 @@ private:
|
||||||
LLTabContainer* mTabContainer;
|
LLTabContainer* mTabContainer;
|
||||||
LLAvatarList* mOnlineFriendList;
|
LLAvatarList* mOnlineFriendList;
|
||||||
LLAvatarList* mAllFriendList;
|
LLAvatarList* mAllFriendList;
|
||||||
|
LLAvatarList* mSuggestedFriends;
|
||||||
LLAvatarList* mNearbyList;
|
LLAvatarList* mNearbyList;
|
||||||
LLAvatarList* mRecentList;
|
LLAvatarList* mRecentList;
|
||||||
LLGroupList* mGroupList;
|
LLGroupList* mGroupList;
|
||||||
|
|
@ -140,6 +148,7 @@ private:
|
||||||
Updater* mFriendListUpdater;
|
Updater* mFriendListUpdater;
|
||||||
Updater* mNearbyListUpdater;
|
Updater* mNearbyListUpdater;
|
||||||
Updater* mRecentListUpdater;
|
Updater* mRecentListUpdater;
|
||||||
|
Updater* mFacebookListUpdater;
|
||||||
Updater* mButtonsUpdater;
|
Updater* mButtonsUpdater;
|
||||||
LLHandle< LLFloater > mPicker;
|
LLHandle< LLFloater > mPicker;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ namespace LLPanelPeopleMenus
|
||||||
|
|
||||||
PeopleContextMenu gPeopleContextMenu;
|
PeopleContextMenu gPeopleContextMenu;
|
||||||
NearbyPeopleContextMenu gNearbyPeopleContextMenu;
|
NearbyPeopleContextMenu gNearbyPeopleContextMenu;
|
||||||
|
SuggestedFriendsContextMenu gSuggestedFriendsContextMenu;
|
||||||
|
|
||||||
//== PeopleContextMenu ===============================================================
|
//== PeopleContextMenu ===============================================================
|
||||||
|
|
||||||
|
|
@ -74,6 +75,7 @@ LLContextMenu* PeopleContextMenu::createMenu()
|
||||||
registrar.add("Avatar.Pay", boost::bind(&LLAvatarActions::pay, id));
|
registrar.add("Avatar.Pay", boost::bind(&LLAvatarActions::pay, id));
|
||||||
registrar.add("Avatar.BlockUnblock", boost::bind(&LLAvatarActions::toggleBlock, id));
|
registrar.add("Avatar.BlockUnblock", boost::bind(&LLAvatarActions::toggleBlock, id));
|
||||||
registrar.add("Avatar.InviteToGroup", boost::bind(&LLAvatarActions::inviteToGroup, id));
|
registrar.add("Avatar.InviteToGroup", boost::bind(&LLAvatarActions::inviteToGroup, id));
|
||||||
|
registrar.add("Avatar.TeleportRequest", boost::bind(&PeopleContextMenu::requestTeleport, this));
|
||||||
registrar.add("Avatar.Calllog", boost::bind(&LLAvatarActions::viewChatHistory, id));
|
registrar.add("Avatar.Calllog", boost::bind(&LLAvatarActions::viewChatHistory, id));
|
||||||
|
|
||||||
enable_registrar.add("Avatar.EnableItem", boost::bind(&PeopleContextMenu::enableContextMenuItem, this, _2));
|
enable_registrar.add("Avatar.EnableItem", boost::bind(&PeopleContextMenu::enableContextMenuItem, this, _2));
|
||||||
|
|
@ -125,6 +127,7 @@ void PeopleContextMenu::buildContextMenu(class LLMenuGL& menu, U32 flags)
|
||||||
items.push_back(std::string("view_profile"));
|
items.push_back(std::string("view_profile"));
|
||||||
items.push_back(std::string("im"));
|
items.push_back(std::string("im"));
|
||||||
items.push_back(std::string("offer_teleport"));
|
items.push_back(std::string("offer_teleport"));
|
||||||
|
items.push_back(std::string("request_teleport"));
|
||||||
items.push_back(std::string("voice_call"));
|
items.push_back(std::string("voice_call"));
|
||||||
items.push_back(std::string("chat_history"));
|
items.push_back(std::string("chat_history"));
|
||||||
items.push_back(std::string("separator_chat_history"));
|
items.push_back(std::string("separator_chat_history"));
|
||||||
|
|
@ -255,6 +258,13 @@ bool PeopleContextMenu::checkContextMenuItem(const LLSD& userdata)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PeopleContextMenu::requestTeleport()
|
||||||
|
{
|
||||||
|
// boost::bind cannot recognize overloaded method LLAvatarActions::teleportRequest(),
|
||||||
|
// so we have to use a wrapper.
|
||||||
|
LLAvatarActions::teleportRequest(mUUIDs.front());
|
||||||
|
}
|
||||||
|
|
||||||
void PeopleContextMenu::offerTeleport()
|
void PeopleContextMenu::offerTeleport()
|
||||||
{
|
{
|
||||||
// boost::bind cannot recognize overloaded method LLAvatarActions::offerTeleport(),
|
// boost::bind cannot recognize overloaded method LLAvatarActions::offerTeleport(),
|
||||||
|
|
@ -284,6 +294,7 @@ void NearbyPeopleContextMenu::buildContextMenu(class LLMenuGL& menu, U32 flags)
|
||||||
items.push_back(std::string("view_profile"));
|
items.push_back(std::string("view_profile"));
|
||||||
items.push_back(std::string("im"));
|
items.push_back(std::string("im"));
|
||||||
items.push_back(std::string("offer_teleport"));
|
items.push_back(std::string("offer_teleport"));
|
||||||
|
items.push_back(std::string("request_teleport"));
|
||||||
items.push_back(std::string("voice_call"));
|
items.push_back(std::string("voice_call"));
|
||||||
items.push_back(std::string("chat_history"));
|
items.push_back(std::string("chat_history"));
|
||||||
items.push_back(std::string("separator_chat_history"));
|
items.push_back(std::string("separator_chat_history"));
|
||||||
|
|
@ -301,4 +312,36 @@ void NearbyPeopleContextMenu::buildContextMenu(class LLMenuGL& menu, U32 flags)
|
||||||
hide_context_entries(menu, items, disabled_items);
|
hide_context_entries(menu, items, disabled_items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//== SuggestedFriendsContextMenu ===============================================================
|
||||||
|
|
||||||
|
LLContextMenu* SuggestedFriendsContextMenu::createMenu()
|
||||||
|
{
|
||||||
|
// set up the callbacks for all of the avatar menu items
|
||||||
|
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
|
||||||
|
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
|
||||||
|
LLContextMenu* menu;
|
||||||
|
|
||||||
|
// Set up for one person selected menu
|
||||||
|
const LLUUID& id = mUUIDs.front();
|
||||||
|
registrar.add("Avatar.Profile", boost::bind(&LLAvatarActions::showProfile, id));
|
||||||
|
registrar.add("Avatar.AddFriend", boost::bind(&LLAvatarActions::requestFriendshipDialog, id));
|
||||||
|
|
||||||
|
// create the context menu from the XUI
|
||||||
|
menu = createFromFile("menu_people_nearby.xml");
|
||||||
|
buildContextMenu(*menu, 0x0);
|
||||||
|
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SuggestedFriendsContextMenu::buildContextMenu(class LLMenuGL& menu, U32 flags)
|
||||||
|
{
|
||||||
|
menuentry_vec_t items;
|
||||||
|
menuentry_vec_t disabled_items;
|
||||||
|
|
||||||
|
items.push_back(std::string("view_profile"));
|
||||||
|
items.push_back(std::string("add_friend"));
|
||||||
|
|
||||||
|
hide_context_entries(menu, items, disabled_items);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace LLPanelPeopleMenus
|
} // namespace LLPanelPeopleMenus
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ private:
|
||||||
bool enableContextMenuItem(const LLSD& userdata);
|
bool enableContextMenuItem(const LLSD& userdata);
|
||||||
bool checkContextMenuItem(const LLSD& userdata);
|
bool checkContextMenuItem(const LLSD& userdata);
|
||||||
void offerTeleport();
|
void offerTeleport();
|
||||||
|
void requestTeleport();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -58,8 +59,21 @@ protected:
|
||||||
/*virtual*/ void buildContextMenu(class LLMenuGL& menu, U32 flags);
|
/*virtual*/ void buildContextMenu(class LLMenuGL& menu, U32 flags);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Menu used in the suggested friends list.
|
||||||
|
*/
|
||||||
|
class SuggestedFriendsContextMenu : public PeopleContextMenu
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*virtual*/ LLContextMenu * createMenu();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*virtual*/ void buildContextMenu(class LLMenuGL& menu, U32 flags);
|
||||||
|
};
|
||||||
|
|
||||||
extern PeopleContextMenu gPeopleContextMenu;
|
extern PeopleContextMenu gPeopleContextMenu;
|
||||||
extern NearbyPeopleContextMenu gNearbyPeopleContextMenu;
|
extern NearbyPeopleContextMenu gNearbyPeopleContextMenu;
|
||||||
|
extern SuggestedFriendsContextMenu gSuggestedFriendsContextMenu;
|
||||||
|
|
||||||
} // namespace LLPanelPeopleMenus
|
} // namespace LLPanelPeopleMenus
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,8 @@ LLPanelPrimMediaControls::LLPanelPrimMediaControls() :
|
||||||
mZoomObjectFace(0),
|
mZoomObjectFace(0),
|
||||||
mVolumeSliderVisible(0),
|
mVolumeSliderVisible(0),
|
||||||
mWindowShade(NULL),
|
mWindowShade(NULL),
|
||||||
mHideImmediately(false)
|
mHideImmediately(false),
|
||||||
|
mSecureURL(false)
|
||||||
{
|
{
|
||||||
mCommitCallbackRegistrar.add("MediaCtrl.Close", boost::bind(&LLPanelPrimMediaControls::onClickClose, this));
|
mCommitCallbackRegistrar.add("MediaCtrl.Close", boost::bind(&LLPanelPrimMediaControls::onClickClose, this));
|
||||||
mCommitCallbackRegistrar.add("MediaCtrl.Back", boost::bind(&LLPanelPrimMediaControls::onClickBack, this));
|
mCommitCallbackRegistrar.add("MediaCtrl.Back", boost::bind(&LLPanelPrimMediaControls::onClickBack, this));
|
||||||
|
|
@ -345,7 +346,7 @@ void LLPanelPrimMediaControls::updateShape()
|
||||||
// Disable zoom if HUD
|
// Disable zoom if HUD
|
||||||
mZoomCtrl->setEnabled(!is_hud);
|
mZoomCtrl->setEnabled(!is_hud);
|
||||||
mUnzoomCtrl->setEnabled(!is_hud);
|
mUnzoomCtrl->setEnabled(!is_hud);
|
||||||
mSecureLockIcon->setVisible(false);
|
mSecureURL = false;
|
||||||
mCurrentURL = media_impl->getCurrentMediaURL();
|
mCurrentURL = media_impl->getCurrentMediaURL();
|
||||||
|
|
||||||
mBackCtrl->setEnabled((media_impl != NULL) && media_impl->canNavigateBack() && can_navigate);
|
mBackCtrl->setEnabled((media_impl != NULL) && media_impl->canNavigateBack() && can_navigate);
|
||||||
|
|
@ -382,7 +383,7 @@ void LLPanelPrimMediaControls::updateShape()
|
||||||
mVolumeSliderCtrl->setVisible(has_focus && shouldVolumeSliderBeVisible());
|
mVolumeSliderCtrl->setVisible(has_focus && shouldVolumeSliderBeVisible());
|
||||||
|
|
||||||
mWhitelistIcon->setVisible(false);
|
mWhitelistIcon->setVisible(false);
|
||||||
mSecureLockIcon->setVisible(false);
|
mSecureURL = false;
|
||||||
if (mMediaPanelScroll)
|
if (mMediaPanelScroll)
|
||||||
{
|
{
|
||||||
mMediaPanelScroll->setVisible(false);
|
mMediaPanelScroll->setVisible(false);
|
||||||
|
|
@ -416,7 +417,7 @@ void LLPanelPrimMediaControls::updateShape()
|
||||||
mMediaPlaySliderCtrl->setEnabled(true);
|
mMediaPlaySliderCtrl->setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// video vloume
|
// video volume
|
||||||
if(volume <= 0.0)
|
if(volume <= 0.0)
|
||||||
{
|
{
|
||||||
mMuteBtn->setToggleState(true);
|
mMuteBtn->setToggleState(true);
|
||||||
|
|
@ -492,10 +493,8 @@ void LLPanelPrimMediaControls::updateShape()
|
||||||
std::string prefix = std::string("https://");
|
std::string prefix = std::string("https://");
|
||||||
std::string test_prefix = mCurrentURL.substr(0, prefix.length());
|
std::string test_prefix = mCurrentURL.substr(0, prefix.length());
|
||||||
LLStringUtil::toLower(test_prefix);
|
LLStringUtil::toLower(test_prefix);
|
||||||
if(test_prefix == prefix)
|
mSecureURL = has_focus && (test_prefix == prefix);
|
||||||
{
|
mCurrentURL = (mSecureURL ? " " + mCurrentURL : mCurrentURL);
|
||||||
mSecureLockIcon->setVisible(has_focus);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mCurrentURL!=mPreviousURL)
|
if(mCurrentURL!=mPreviousURL)
|
||||||
{
|
{
|
||||||
|
|
@ -746,6 +745,9 @@ void LLPanelPrimMediaControls::draw()
|
||||||
clearFaceOnFade();
|
clearFaceOnFade();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show/hide the lock icon for secure browsing
|
||||||
|
mSecureLockIcon->setVisible(mSecureURL && !mMediaAddress->hasFocus());
|
||||||
|
|
||||||
// Build rect for icon area in coord system of this panel
|
// Build rect for icon area in coord system of this panel
|
||||||
// Assumes layout_stack is a direct child of this panel
|
// Assumes layout_stack is a direct child of this panel
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,7 @@ private:
|
||||||
bool mUpdateSlider;
|
bool mUpdateSlider;
|
||||||
bool mClearFaceOnFade;
|
bool mClearFaceOnFade;
|
||||||
bool mHideImmediately;
|
bool mHideImmediately;
|
||||||
|
bool mSecureURL;
|
||||||
|
|
||||||
LLMatrix4 mLastCameraMat;
|
LLMatrix4 mLastCameraMat;
|
||||||
EZoomLevel mCurrentZoom;
|
EZoomLevel mCurrentZoom;
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include "llviewerprecompiledheaders.h"
|
#include "llviewerprecompiledheaders.h"
|
||||||
|
|
||||||
#include "llavatarnamecache.h"
|
#include "llavatarnamecache.h"
|
||||||
|
#include "llerror.h"
|
||||||
#include "llimview.h"
|
#include "llimview.h"
|
||||||
#include "llfloaterimcontainer.h"
|
#include "llfloaterimcontainer.h"
|
||||||
#include "llparticipantlist.h"
|
#include "llparticipantlist.h"
|
||||||
|
|
@ -401,6 +402,8 @@ void LLParticipantList::addAvatarIDExceptAgent(const LLUUID& avatar_id)
|
||||||
adjustParticipant(avatar_id);
|
adjustParticipant(avatar_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LLFastTimer::DeclareTimer FTM_FOLDERVIEW_TEST("add test avatar agents");
|
||||||
|
|
||||||
void LLParticipantList::adjustParticipant(const LLUUID& speaker_id)
|
void LLParticipantList::adjustParticipant(const LLUUID& speaker_id)
|
||||||
{
|
{
|
||||||
LLPointer<LLSpeaker> speakerp = mSpeakerMgr->findSpeaker(speaker_id);
|
LLPointer<LLSpeaker> speakerp = mSpeakerMgr->findSpeaker(speaker_id);
|
||||||
|
|
|
||||||
|
|
@ -207,6 +207,7 @@ LLSD _basic_constraints_ext(X509* cert)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BASIC_CONSTRAINTS_free( bs );
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -268,6 +269,8 @@ LLSD _ext_key_usage_ext(X509* cert)
|
||||||
ASN1_OBJECT_free(usage);
|
ASN1_OBJECT_free(usage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXTENDED_KEY_USAGE_free( eku );
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -280,6 +283,8 @@ LLSD _subject_key_identifier_ext(X509 *cert)
|
||||||
if(skeyid)
|
if(skeyid)
|
||||||
{
|
{
|
||||||
result = cert_string_from_octet_string(skeyid);
|
result = cert_string_from_octet_string(skeyid);
|
||||||
|
|
||||||
|
ASN1_OCTET_STRING_free( skeyid );
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -300,6 +305,9 @@ LLSD _authority_key_identifier_ext(X509* cert)
|
||||||
{
|
{
|
||||||
result[CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL] = cert_string_from_asn1_integer(akeyid->serial);
|
result[CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL] = cert_string_from_asn1_integer(akeyid->serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AUTHORITY_KEYID_free( akeyid );
|
||||||
}
|
}
|
||||||
|
|
||||||
// we ignore the issuer name in the authority key identifier, we check the issue name via
|
// we ignore the issuer name in the authority key identifier, we check the issue name via
|
||||||
|
|
@ -1049,6 +1057,8 @@ void LLBasicCertificateStore::validate(int validation_policy,
|
||||||
throw LLInvalidCertificate((*current_cert));
|
throw LLInvalidCertificate((*current_cert));
|
||||||
}
|
}
|
||||||
std::string sha1_hash((const char *)cert_x509->sha1_hash, SHA_DIGEST_LENGTH);
|
std::string sha1_hash((const char *)cert_x509->sha1_hash, SHA_DIGEST_LENGTH);
|
||||||
|
X509_free( cert_x509 );
|
||||||
|
cert_x509 = NULL;
|
||||||
t_cert_cache::iterator cache_entry = mTrustedCertCache.find(sha1_hash);
|
t_cert_cache::iterator cache_entry = mTrustedCertCache.find(sha1_hash);
|
||||||
if(cache_entry != mTrustedCertCache.end())
|
if(cache_entry != mTrustedCertCache.end())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,874 @@
|
||||||
|
/**
|
||||||
|
* @file llsnapshotlivepreview.cpp
|
||||||
|
* @brief Implementation of llsnapshotlivepreview
|
||||||
|
* @author Gilbert@lindenlab.com
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
|
||||||
|
* Second Life Viewer Source Code
|
||||||
|
* Copyright (C) 2013, Linden Research, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation;
|
||||||
|
* version 2.1 of the License only.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
|
* $/LicenseInfo$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "llviewerprecompiledheaders.h"
|
||||||
|
|
||||||
|
#include "llagent.h"
|
||||||
|
#include "llagentcamera.h"
|
||||||
|
#include "llagentui.h"
|
||||||
|
#include "llcombobox.h"
|
||||||
|
#include "lleconomy.h"
|
||||||
|
#include "llfloaterperms.h"
|
||||||
|
#include "llfloaterreg.h"
|
||||||
|
#include "llfloatersocial.h"
|
||||||
|
#include "llimagebmp.h"
|
||||||
|
#include "llimagej2c.h"
|
||||||
|
#include "llimagejpeg.h"
|
||||||
|
#include "llimagepng.h"
|
||||||
|
#include "lllandmarkactions.h"
|
||||||
|
#include "lllocalcliprect.h"
|
||||||
|
#include "llnotificationsutil.h"
|
||||||
|
#include "llslurl.h"
|
||||||
|
#include "llsnapshotlivepreview.h"
|
||||||
|
#include "lltoolfocus.h"
|
||||||
|
#include "llviewercontrol.h"
|
||||||
|
#include "llviewermenufile.h" // upload_new_resource()
|
||||||
|
#include "llviewerstats.h"
|
||||||
|
#include "llvfile.h"
|
||||||
|
#include "llvfs.h"
|
||||||
|
#include "llwebsharing.h"
|
||||||
|
#include "llwindow.h"
|
||||||
|
#include "llworld.h"
|
||||||
|
|
||||||
|
const F32 AUTO_SNAPSHOT_TIME_DELAY = 1.f;
|
||||||
|
|
||||||
|
F32 SHINE_TIME = 0.5f;
|
||||||
|
F32 SHINE_WIDTH = 0.6f;
|
||||||
|
F32 SHINE_OPACITY = 0.3f;
|
||||||
|
F32 FALL_TIME = 0.6f;
|
||||||
|
S32 BORDER_WIDTH = 6;
|
||||||
|
|
||||||
|
const S32 MAX_TEXTURE_SIZE = 512 ; //max upload texture size 512 * 512
|
||||||
|
|
||||||
|
std::set<LLSnapshotLivePreview*> LLSnapshotLivePreview::sList;
|
||||||
|
|
||||||
|
LLSnapshotLivePreview::LLSnapshotLivePreview (const LLSnapshotLivePreview::Params& p)
|
||||||
|
: LLView(p),
|
||||||
|
mColor(1.f, 0.f, 0.f, 0.5f),
|
||||||
|
mCurImageIndex(0),
|
||||||
|
mPreviewImage(NULL),
|
||||||
|
mThumbnailImage(NULL) ,
|
||||||
|
mThumbnailWidth(0),
|
||||||
|
mThumbnailHeight(0),
|
||||||
|
mPreviewImageEncoded(NULL),
|
||||||
|
mFormattedImage(NULL),
|
||||||
|
mShineCountdown(0),
|
||||||
|
mFlashAlpha(0.f),
|
||||||
|
mNeedsFlash(TRUE),
|
||||||
|
mSnapshotQuality(gSavedSettings.getS32("SnapshotQuality")),
|
||||||
|
mDataSize(0),
|
||||||
|
mSnapshotType(SNAPSHOT_POSTCARD),
|
||||||
|
mSnapshotFormat(LLFloaterSnapshot::ESnapshotFormat(gSavedSettings.getS32("SnapshotFormat"))),
|
||||||
|
mSnapshotUpToDate(FALSE),
|
||||||
|
mCameraPos(LLViewerCamera::getInstance()->getOrigin()),
|
||||||
|
mCameraRot(LLViewerCamera::getInstance()->getQuaternion()),
|
||||||
|
mSnapshotActive(FALSE),
|
||||||
|
mSnapshotBufferType(LLViewerWindow::SNAPSHOT_TYPE_COLOR)
|
||||||
|
{
|
||||||
|
setSnapshotQuality(gSavedSettings.getS32("SnapshotQuality"));
|
||||||
|
mSnapshotDelayTimer.setTimerExpirySec(0.0f);
|
||||||
|
mSnapshotDelayTimer.start();
|
||||||
|
// gIdleCallbacks.addFunction( &LLSnapshotLivePreview::onIdle, (void*)this );
|
||||||
|
sList.insert(this);
|
||||||
|
setFollowsAll();
|
||||||
|
mWidth[0] = gViewerWindow->getWindowWidthRaw();
|
||||||
|
mWidth[1] = gViewerWindow->getWindowWidthRaw();
|
||||||
|
mHeight[0] = gViewerWindow->getWindowHeightRaw();
|
||||||
|
mHeight[1] = gViewerWindow->getWindowHeightRaw();
|
||||||
|
mImageScaled[0] = FALSE;
|
||||||
|
mImageScaled[1] = FALSE;
|
||||||
|
|
||||||
|
mMaxImageSize = MAX_SNAPSHOT_IMAGE_SIZE ;
|
||||||
|
mKeepAspectRatio = gSavedSettings.getBOOL("KeepAspectForSnapshot") ;
|
||||||
|
mThumbnailUpdateLock = FALSE ;
|
||||||
|
mThumbnailUpToDate = FALSE ;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLSnapshotLivePreview::~LLSnapshotLivePreview()
|
||||||
|
{
|
||||||
|
// delete images
|
||||||
|
mPreviewImage = NULL;
|
||||||
|
mPreviewImageEncoded = NULL;
|
||||||
|
mFormattedImage = NULL;
|
||||||
|
|
||||||
|
// gIdleCallbacks.deleteFunction( &LLSnapshotLivePreview::onIdle, (void*)this );
|
||||||
|
sList.erase(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSnapshotLivePreview::setMaxImageSize(S32 size)
|
||||||
|
{
|
||||||
|
if(size < MAX_SNAPSHOT_IMAGE_SIZE)
|
||||||
|
{
|
||||||
|
mMaxImageSize = size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mMaxImageSize = MAX_SNAPSHOT_IMAGE_SIZE ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LLViewerTexture* LLSnapshotLivePreview::getCurrentImage()
|
||||||
|
{
|
||||||
|
return mViewerImage[mCurImageIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
F32 LLSnapshotLivePreview::getAspect()
|
||||||
|
{
|
||||||
|
F32 image_aspect_ratio = ((F32)getWidth()) / ((F32)getHeight());
|
||||||
|
F32 window_aspect_ratio = ((F32)getRect().getWidth()) / ((F32)getRect().getHeight());
|
||||||
|
|
||||||
|
if (!mKeepAspectRatio)//gSavedSettings.getBOOL("KeepAspectForSnapshot"))
|
||||||
|
{
|
||||||
|
return image_aspect_ratio;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return window_aspect_ratio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
F32 LLSnapshotLivePreview::getImageAspect()
|
||||||
|
{
|
||||||
|
if (!getCurrentImage())
|
||||||
|
{
|
||||||
|
return 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getAspect() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail, F32 delay)
|
||||||
|
{
|
||||||
|
// Invalidate current image.
|
||||||
|
lldebugs << "updateSnapshot: mSnapshotUpToDate = " << getSnapshotUpToDate() << llendl;
|
||||||
|
if (getSnapshotUpToDate())
|
||||||
|
{
|
||||||
|
S32 old_image_index = mCurImageIndex;
|
||||||
|
mCurImageIndex = (mCurImageIndex + 1) % 2;
|
||||||
|
setSize(mWidth[old_image_index], mHeight[old_image_index]);
|
||||||
|
mFallAnimTimer.start();
|
||||||
|
}
|
||||||
|
mSnapshotUpToDate = FALSE;
|
||||||
|
|
||||||
|
// Update snapshot source rect depending on whether we keep the aspect ratio.
|
||||||
|
LLRect& rect = mImageRect[mCurImageIndex];
|
||||||
|
rect.set(0, getRect().getHeight(), getRect().getWidth(), 0);
|
||||||
|
|
||||||
|
F32 image_aspect_ratio = ((F32)getWidth()) / ((F32)getHeight());
|
||||||
|
F32 window_aspect_ratio = ((F32)getRect().getWidth()) / ((F32)getRect().getHeight());
|
||||||
|
|
||||||
|
if (mKeepAspectRatio)//gSavedSettings.getBOOL("KeepAspectForSnapshot"))
|
||||||
|
{
|
||||||
|
if (image_aspect_ratio > window_aspect_ratio)
|
||||||
|
{
|
||||||
|
// trim off top and bottom
|
||||||
|
S32 new_height = llround((F32)getRect().getWidth() / image_aspect_ratio);
|
||||||
|
rect.mBottom += (getRect().getHeight() - new_height) / 2;
|
||||||
|
rect.mTop -= (getRect().getHeight() - new_height) / 2;
|
||||||
|
}
|
||||||
|
else if (image_aspect_ratio < window_aspect_ratio)
|
||||||
|
{
|
||||||
|
// trim off left and right
|
||||||
|
S32 new_width = llround((F32)getRect().getHeight() * image_aspect_ratio);
|
||||||
|
rect.mLeft += (getRect().getWidth() - new_width) / 2;
|
||||||
|
rect.mRight -= (getRect().getWidth() - new_width) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop shining animation.
|
||||||
|
mShineAnimTimer.stop();
|
||||||
|
|
||||||
|
// Update snapshot if requested.
|
||||||
|
if (new_snapshot)
|
||||||
|
{
|
||||||
|
mSnapshotDelayTimer.start();
|
||||||
|
mSnapshotDelayTimer.setTimerExpirySec(delay);
|
||||||
|
LLFloaterSnapshot::preUpdate();
|
||||||
|
LLFloaterSocial::preUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update thumbnail if requested.
|
||||||
|
if(new_thumbnail)
|
||||||
|
{
|
||||||
|
mThumbnailUpToDate = FALSE ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSnapshotLivePreview::setSnapshotQuality(S32 quality)
|
||||||
|
{
|
||||||
|
llclamp(quality, 0, 100);
|
||||||
|
if (quality != mSnapshotQuality)
|
||||||
|
{
|
||||||
|
mSnapshotQuality = quality;
|
||||||
|
gSavedSettings.setS32("SnapshotQuality", quality);
|
||||||
|
mSnapshotUpToDate = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSnapshotLivePreview::drawPreviewRect(S32 offset_x, S32 offset_y)
|
||||||
|
{
|
||||||
|
F32 line_width ;
|
||||||
|
glGetFloatv(GL_LINE_WIDTH, &line_width) ;
|
||||||
|
glLineWidth(2.0f * line_width) ;
|
||||||
|
LLColor4 color(0.0f, 0.0f, 0.0f, 1.0f) ;
|
||||||
|
gl_rect_2d( mPreviewRect.mLeft + offset_x, mPreviewRect.mTop + offset_y,
|
||||||
|
mPreviewRect.mRight + offset_x, mPreviewRect.mBottom + offset_y, color, FALSE ) ;
|
||||||
|
glLineWidth(line_width) ;
|
||||||
|
|
||||||
|
//draw four alpha rectangles to cover areas outside of the snapshot image
|
||||||
|
if(!mKeepAspectRatio)
|
||||||
|
{
|
||||||
|
LLColor4 alpha_color(0.5f, 0.5f, 0.5f, 0.8f) ;
|
||||||
|
S32 dwl = 0, dwr = 0 ;
|
||||||
|
if(mThumbnailWidth > mPreviewRect.getWidth())
|
||||||
|
{
|
||||||
|
dwl = (mThumbnailWidth - mPreviewRect.getWidth()) >> 1 ;
|
||||||
|
dwr = mThumbnailWidth - mPreviewRect.getWidth() - dwl ;
|
||||||
|
|
||||||
|
gl_rect_2d(mPreviewRect.mLeft + offset_x - dwl, mPreviewRect.mTop + offset_y,
|
||||||
|
mPreviewRect.mLeft + offset_x, mPreviewRect.mBottom + offset_y, alpha_color, TRUE ) ;
|
||||||
|
gl_rect_2d( mPreviewRect.mRight + offset_x, mPreviewRect.mTop + offset_y,
|
||||||
|
mPreviewRect.mRight + offset_x + dwr, mPreviewRect.mBottom + offset_y, alpha_color, TRUE ) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mThumbnailHeight > mPreviewRect.getHeight())
|
||||||
|
{
|
||||||
|
S32 dh = (mThumbnailHeight - mPreviewRect.getHeight()) >> 1 ;
|
||||||
|
gl_rect_2d(mPreviewRect.mLeft + offset_x - dwl, mPreviewRect.mBottom + offset_y ,
|
||||||
|
mPreviewRect.mRight + offset_x + dwr, mPreviewRect.mBottom + offset_y - dh, alpha_color, TRUE ) ;
|
||||||
|
|
||||||
|
dh = mThumbnailHeight - mPreviewRect.getHeight() - dh ;
|
||||||
|
gl_rect_2d( mPreviewRect.mLeft + offset_x - dwl, mPreviewRect.mTop + offset_y + dh,
|
||||||
|
mPreviewRect.mRight + offset_x + dwr, mPreviewRect.mTop + offset_y, alpha_color, TRUE ) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//called when the frame is frozen.
|
||||||
|
void LLSnapshotLivePreview::draw()
|
||||||
|
{
|
||||||
|
if (getCurrentImage() &&
|
||||||
|
mPreviewImageEncoded.notNull() &&
|
||||||
|
getSnapshotUpToDate())
|
||||||
|
{
|
||||||
|
LLColor4 bg_color(0.f, 0.f, 0.3f, 0.4f);
|
||||||
|
gl_rect_2d(getRect(), bg_color);
|
||||||
|
const LLRect& rect = getImageRect();
|
||||||
|
LLRect shadow_rect = rect;
|
||||||
|
shadow_rect.stretch(BORDER_WIDTH);
|
||||||
|
gl_drop_shadow(shadow_rect.mLeft, shadow_rect.mTop, shadow_rect.mRight, shadow_rect.mBottom, LLColor4(0.f, 0.f, 0.f, mNeedsFlash ? 0.f :0.5f), 10);
|
||||||
|
|
||||||
|
LLColor4 image_color(1.f, 1.f, 1.f, 1.f);
|
||||||
|
gGL.color4fv(image_color.mV);
|
||||||
|
gGL.getTexUnit(0)->bind(getCurrentImage());
|
||||||
|
// calculate UV scale
|
||||||
|
F32 uv_width = isImageScaled() ? 1.f : llmin((F32)getWidth() / (F32)getCurrentImage()->getWidth(), 1.f);
|
||||||
|
F32 uv_height = isImageScaled() ? 1.f : llmin((F32)getHeight() / (F32)getCurrentImage()->getHeight(), 1.f);
|
||||||
|
gGL.pushMatrix();
|
||||||
|
{
|
||||||
|
gGL.translatef((F32)rect.mLeft, (F32)rect.mBottom, 0.f);
|
||||||
|
gGL.begin(LLRender::QUADS);
|
||||||
|
{
|
||||||
|
gGL.texCoord2f(uv_width, uv_height);
|
||||||
|
gGL.vertex2i(rect.getWidth(), rect.getHeight() );
|
||||||
|
|
||||||
|
gGL.texCoord2f(0.f, uv_height);
|
||||||
|
gGL.vertex2i(0, rect.getHeight() );
|
||||||
|
|
||||||
|
gGL.texCoord2f(0.f, 0.f);
|
||||||
|
gGL.vertex2i(0, 0);
|
||||||
|
|
||||||
|
gGL.texCoord2f(uv_width, 0.f);
|
||||||
|
gGL.vertex2i(rect.getWidth(), 0);
|
||||||
|
}
|
||||||
|
gGL.end();
|
||||||
|
}
|
||||||
|
gGL.popMatrix();
|
||||||
|
|
||||||
|
gGL.color4f(1.f, 1.f, 1.f, mFlashAlpha);
|
||||||
|
gl_rect_2d(getRect());
|
||||||
|
if (mNeedsFlash)
|
||||||
|
{
|
||||||
|
if (mFlashAlpha < 1.f)
|
||||||
|
{
|
||||||
|
mFlashAlpha = lerp(mFlashAlpha, 1.f, LLCriticalDamp::getInterpolant(0.02f));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mNeedsFlash = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mFlashAlpha = lerp(mFlashAlpha, 0.f, LLCriticalDamp::getInterpolant(0.15f));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw shining animation if appropriate.
|
||||||
|
if (mShineCountdown > 0)
|
||||||
|
{
|
||||||
|
mShineCountdown--;
|
||||||
|
if (mShineCountdown == 0)
|
||||||
|
{
|
||||||
|
mShineAnimTimer.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mShineAnimTimer.getStarted())
|
||||||
|
{
|
||||||
|
lldebugs << "Drawing shining animation" << llendl;
|
||||||
|
F32 shine_interp = llmin(1.f, mShineAnimTimer.getElapsedTimeF32() / SHINE_TIME);
|
||||||
|
|
||||||
|
// draw "shine" effect
|
||||||
|
LLLocalClipRect clip(getLocalRect());
|
||||||
|
{
|
||||||
|
// draw diagonal stripe with gradient that passes over screen
|
||||||
|
S32 x1 = gViewerWindow->getWindowWidthScaled() * llround((clamp_rescale(shine_interp, 0.f, 1.f, -1.f - SHINE_WIDTH, 1.f)));
|
||||||
|
S32 x2 = x1 + llround(gViewerWindow->getWindowWidthScaled() * SHINE_WIDTH);
|
||||||
|
S32 x3 = x2 + llround(gViewerWindow->getWindowWidthScaled() * SHINE_WIDTH);
|
||||||
|
S32 y1 = 0;
|
||||||
|
S32 y2 = gViewerWindow->getWindowHeightScaled();
|
||||||
|
|
||||||
|
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||||
|
gGL.begin(LLRender::QUADS);
|
||||||
|
{
|
||||||
|
gGL.color4f(1.f, 1.f, 1.f, 0.f);
|
||||||
|
gGL.vertex2i(x1, y1);
|
||||||
|
gGL.vertex2i(x1 + gViewerWindow->getWindowWidthScaled(), y2);
|
||||||
|
gGL.color4f(1.f, 1.f, 1.f, SHINE_OPACITY);
|
||||||
|
gGL.vertex2i(x2 + gViewerWindow->getWindowWidthScaled(), y2);
|
||||||
|
gGL.vertex2i(x2, y1);
|
||||||
|
|
||||||
|
gGL.color4f(1.f, 1.f, 1.f, SHINE_OPACITY);
|
||||||
|
gGL.vertex2i(x2, y1);
|
||||||
|
gGL.vertex2i(x2 + gViewerWindow->getWindowWidthScaled(), y2);
|
||||||
|
gGL.color4f(1.f, 1.f, 1.f, 0.f);
|
||||||
|
gGL.vertex2i(x3 + gViewerWindow->getWindowWidthScaled(), y2);
|
||||||
|
gGL.vertex2i(x3, y1);
|
||||||
|
}
|
||||||
|
gGL.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we're at the end of the animation, stop
|
||||||
|
if (shine_interp >= 1.f)
|
||||||
|
{
|
||||||
|
mShineAnimTimer.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw framing rectangle
|
||||||
|
{
|
||||||
|
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||||
|
gGL.color4f(1.f, 1.f, 1.f, 1.f);
|
||||||
|
const LLRect& outline_rect = getImageRect();
|
||||||
|
gGL.begin(LLRender::QUADS);
|
||||||
|
{
|
||||||
|
gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
|
||||||
|
gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
|
||||||
|
gGL.vertex2i(outline_rect.mRight, outline_rect.mTop);
|
||||||
|
gGL.vertex2i(outline_rect.mLeft, outline_rect.mTop);
|
||||||
|
|
||||||
|
gGL.vertex2i(outline_rect.mLeft, outline_rect.mBottom);
|
||||||
|
gGL.vertex2i(outline_rect.mRight, outline_rect.mBottom);
|
||||||
|
gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
|
||||||
|
gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
|
||||||
|
|
||||||
|
gGL.vertex2i(outline_rect.mLeft, outline_rect.mTop);
|
||||||
|
gGL.vertex2i(outline_rect.mLeft, outline_rect.mBottom);
|
||||||
|
gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
|
||||||
|
gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
|
||||||
|
|
||||||
|
gGL.vertex2i(outline_rect.mRight, outline_rect.mBottom);
|
||||||
|
gGL.vertex2i(outline_rect.mRight, outline_rect.mTop);
|
||||||
|
gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
|
||||||
|
gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
|
||||||
|
}
|
||||||
|
gGL.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw old image dropping away
|
||||||
|
if (mFallAnimTimer.getStarted())
|
||||||
|
{
|
||||||
|
S32 old_image_index = (mCurImageIndex + 1) % 2;
|
||||||
|
if (mViewerImage[old_image_index].notNull() && mFallAnimTimer.getElapsedTimeF32() < FALL_TIME)
|
||||||
|
{
|
||||||
|
lldebugs << "Drawing fall animation" << llendl;
|
||||||
|
F32 fall_interp = mFallAnimTimer.getElapsedTimeF32() / FALL_TIME;
|
||||||
|
F32 alpha = clamp_rescale(fall_interp, 0.f, 1.f, 0.8f, 0.4f);
|
||||||
|
LLColor4 image_color(1.f, 1.f, 1.f, alpha);
|
||||||
|
gGL.color4fv(image_color.mV);
|
||||||
|
gGL.getTexUnit(0)->bind(mViewerImage[old_image_index]);
|
||||||
|
// calculate UV scale
|
||||||
|
// *FIX get this to work with old image
|
||||||
|
BOOL rescale = !mImageScaled[old_image_index] && mViewerImage[mCurImageIndex].notNull();
|
||||||
|
F32 uv_width = rescale ? llmin((F32)mWidth[old_image_index] / (F32)mViewerImage[mCurImageIndex]->getWidth(), 1.f) : 1.f;
|
||||||
|
F32 uv_height = rescale ? llmin((F32)mHeight[old_image_index] / (F32)mViewerImage[mCurImageIndex]->getHeight(), 1.f) : 1.f;
|
||||||
|
gGL.pushMatrix();
|
||||||
|
{
|
||||||
|
LLRect& rect = mImageRect[old_image_index];
|
||||||
|
gGL.translatef((F32)rect.mLeft, (F32)rect.mBottom - llround(getRect().getHeight() * 2.f * (fall_interp * fall_interp)), 0.f);
|
||||||
|
gGL.rotatef(-45.f * fall_interp, 0.f, 0.f, 1.f);
|
||||||
|
gGL.begin(LLRender::QUADS);
|
||||||
|
{
|
||||||
|
gGL.texCoord2f(uv_width, uv_height);
|
||||||
|
gGL.vertex2i(rect.getWidth(), rect.getHeight() );
|
||||||
|
|
||||||
|
gGL.texCoord2f(0.f, uv_height);
|
||||||
|
gGL.vertex2i(0, rect.getHeight() );
|
||||||
|
|
||||||
|
gGL.texCoord2f(0.f, 0.f);
|
||||||
|
gGL.vertex2i(0, 0);
|
||||||
|
|
||||||
|
gGL.texCoord2f(uv_width, 0.f);
|
||||||
|
gGL.vertex2i(rect.getWidth(), 0);
|
||||||
|
}
|
||||||
|
gGL.end();
|
||||||
|
}
|
||||||
|
gGL.popMatrix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/
|
||||||
|
void LLSnapshotLivePreview::reshape(S32 width, S32 height, BOOL called_from_parent)
|
||||||
|
{
|
||||||
|
LLRect old_rect = getRect();
|
||||||
|
LLView::reshape(width, height, called_from_parent);
|
||||||
|
if (old_rect.getWidth() != width || old_rect.getHeight() != height)
|
||||||
|
{
|
||||||
|
lldebugs << "window reshaped, updating thumbnail" << llendl;
|
||||||
|
updateSnapshot(FALSE, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL LLSnapshotLivePreview::setThumbnailImageSize()
|
||||||
|
{
|
||||||
|
if(getWidth() < 10 || getHeight() < 10)
|
||||||
|
{
|
||||||
|
return FALSE ;
|
||||||
|
}
|
||||||
|
S32 window_width = gViewerWindow->getWindowWidthRaw() ;
|
||||||
|
S32 window_height = gViewerWindow->getWindowHeightRaw() ;
|
||||||
|
|
||||||
|
F32 window_aspect_ratio = ((F32)window_width) / ((F32)window_height);
|
||||||
|
|
||||||
|
// UI size for thumbnail
|
||||||
|
// *FIXME: the rect does not change, so maybe there's no need to recalculate max w/h.
|
||||||
|
const LLRect& thumbnail_rect = mThumbnailPlaceholderRect;
|
||||||
|
S32 max_width = thumbnail_rect.getWidth();
|
||||||
|
S32 max_height = thumbnail_rect.getHeight();
|
||||||
|
|
||||||
|
if (window_aspect_ratio > (F32)max_width / max_height)
|
||||||
|
{
|
||||||
|
// image too wide, shrink to width
|
||||||
|
mThumbnailWidth = max_width;
|
||||||
|
mThumbnailHeight = llround((F32)max_width / window_aspect_ratio);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// image too tall, shrink to height
|
||||||
|
mThumbnailHeight = max_height;
|
||||||
|
mThumbnailWidth = llround((F32)max_height * window_aspect_ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mThumbnailWidth > window_width || mThumbnailHeight > window_height)
|
||||||
|
{
|
||||||
|
return FALSE ;//if the window is too small, ignore thumbnail updating.
|
||||||
|
}
|
||||||
|
|
||||||
|
S32 left = 0 , top = mThumbnailHeight, right = mThumbnailWidth, bottom = 0 ;
|
||||||
|
if(!mKeepAspectRatio)
|
||||||
|
{
|
||||||
|
F32 ratio_x = (F32)getWidth() / window_width ;
|
||||||
|
F32 ratio_y = (F32)getHeight() / window_height ;
|
||||||
|
|
||||||
|
//if(getWidth() > window_width ||
|
||||||
|
// getHeight() > window_height )
|
||||||
|
{
|
||||||
|
if(ratio_x > ratio_y)
|
||||||
|
{
|
||||||
|
top = (S32)(top * ratio_y / ratio_x) ;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
right = (S32)(right * ratio_x / ratio_y) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
// right = (S32)(right * ratio_x) ;
|
||||||
|
// top = (S32)(top * ratio_y) ;
|
||||||
|
//}
|
||||||
|
left = (S32)((mThumbnailWidth - right) * 0.5f) ;
|
||||||
|
bottom = (S32)((mThumbnailHeight - top) * 0.5f) ;
|
||||||
|
top += bottom ;
|
||||||
|
right += left ;
|
||||||
|
}
|
||||||
|
mPreviewRect.set(left - 1, top + 1, right + 1, bottom - 1) ;
|
||||||
|
|
||||||
|
return TRUE ;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSnapshotLivePreview::generateThumbnailImage(BOOL force_update)
|
||||||
|
{
|
||||||
|
if(mThumbnailUpdateLock) //in the process of updating
|
||||||
|
{
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
if(getThumbnailUpToDate() && !force_update)//already updated
|
||||||
|
{
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
if(getWidth() < 10 || getHeight() < 10)
|
||||||
|
{
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
////lock updating
|
||||||
|
mThumbnailUpdateLock = TRUE ;
|
||||||
|
|
||||||
|
if(!setThumbnailImageSize())
|
||||||
|
{
|
||||||
|
mThumbnailUpdateLock = FALSE ;
|
||||||
|
mThumbnailUpToDate = TRUE ;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mThumbnailImage)
|
||||||
|
{
|
||||||
|
resetThumbnailImage() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLPointer<LLImageRaw> raw = new LLImageRaw;
|
||||||
|
if(!gViewerWindow->thumbnailSnapshot(raw,
|
||||||
|
mThumbnailWidth, mThumbnailHeight,
|
||||||
|
gSavedSettings.getBOOL("RenderUIInSnapshot"),
|
||||||
|
FALSE,
|
||||||
|
mSnapshotBufferType) )
|
||||||
|
{
|
||||||
|
raw = NULL ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(raw)
|
||||||
|
{
|
||||||
|
raw->expandToPowerOfTwo();
|
||||||
|
mThumbnailImage = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE);
|
||||||
|
mThumbnailUpToDate = TRUE ;
|
||||||
|
}
|
||||||
|
|
||||||
|
//unlock updating
|
||||||
|
mThumbnailUpdateLock = FALSE ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Called often. Checks whether it's time to grab a new snapshot and if so, does it.
|
||||||
|
// Returns TRUE if new snapshot generated, FALSE otherwise.
|
||||||
|
//static
|
||||||
|
BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
|
||||||
|
{
|
||||||
|
LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)snapshot_preview;
|
||||||
|
if (previewp->getWidth() == 0 || previewp->getHeight() == 0)
|
||||||
|
{
|
||||||
|
llwarns << "Incorrect dimensions: " << previewp->getWidth() << "x" << previewp->getHeight() << llendl;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're in freeze-frame mode and camera has moved, update snapshot.
|
||||||
|
LLVector3 new_camera_pos = LLViewerCamera::getInstance()->getOrigin();
|
||||||
|
LLQuaternion new_camera_rot = LLViewerCamera::getInstance()->getQuaternion();
|
||||||
|
if (gSavedSettings.getBOOL("FreezeTime") &&
|
||||||
|
(new_camera_pos != previewp->mCameraPos || dot(new_camera_rot, previewp->mCameraRot) < 0.995f))
|
||||||
|
{
|
||||||
|
previewp->mCameraPos = new_camera_pos;
|
||||||
|
previewp->mCameraRot = new_camera_rot;
|
||||||
|
// request a new snapshot whenever the camera moves, with a time delay
|
||||||
|
BOOL autosnap = gSavedSettings.getBOOL("AutoSnapshot");
|
||||||
|
lldebugs << "camera moved, updating thumbnail" << llendl;
|
||||||
|
previewp->updateSnapshot(
|
||||||
|
autosnap, // whether a new snapshot is needed or merely invalidate the existing one
|
||||||
|
FALSE, // or if 1st arg is false, whether to produce a new thumbnail image.
|
||||||
|
autosnap ? AUTO_SNAPSHOT_TIME_DELAY : 0.f); // shutter delay if 1st arg is true.
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if it's time yet to snap the shot and bomb out otherwise.
|
||||||
|
previewp->mSnapshotActive =
|
||||||
|
(previewp->mSnapshotDelayTimer.getStarted() && previewp->mSnapshotDelayTimer.hasExpired())
|
||||||
|
&& !LLToolCamera::getInstance()->hasMouseCapture(); // don't take snapshots while ALT-zoom active
|
||||||
|
if ( ! previewp->mSnapshotActive)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// time to produce a snapshot
|
||||||
|
previewp->setThumbnailImageSize();
|
||||||
|
|
||||||
|
lldebugs << "producing snapshot" << llendl;
|
||||||
|
if (!previewp->mPreviewImage)
|
||||||
|
{
|
||||||
|
previewp->mPreviewImage = new LLImageRaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!previewp->mPreviewImageEncoded)
|
||||||
|
{
|
||||||
|
previewp->mPreviewImageEncoded = new LLImageRaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
previewp->setVisible(FALSE);
|
||||||
|
previewp->setEnabled(FALSE);
|
||||||
|
|
||||||
|
previewp->getWindow()->incBusyCount();
|
||||||
|
previewp->setImageScaled(FALSE);
|
||||||
|
|
||||||
|
// grab the raw image and encode it into desired format
|
||||||
|
if(gViewerWindow->rawSnapshot(
|
||||||
|
previewp->mPreviewImage,
|
||||||
|
previewp->getWidth(),
|
||||||
|
previewp->getHeight(),
|
||||||
|
previewp->mKeepAspectRatio,//gSavedSettings.getBOOL("KeepAspectForSnapshot"),
|
||||||
|
previewp->getSnapshotType() == LLSnapshotLivePreview::SNAPSHOT_TEXTURE,
|
||||||
|
gSavedSettings.getBOOL("RenderUIInSnapshot"),
|
||||||
|
FALSE,
|
||||||
|
previewp->mSnapshotBufferType,
|
||||||
|
previewp->getMaxImageSize()))
|
||||||
|
{
|
||||||
|
previewp->mPreviewImageEncoded->resize(
|
||||||
|
previewp->mPreviewImage->getWidth(),
|
||||||
|
previewp->mPreviewImage->getHeight(),
|
||||||
|
previewp->mPreviewImage->getComponents());
|
||||||
|
|
||||||
|
if(previewp->getSnapshotType() == SNAPSHOT_TEXTURE)
|
||||||
|
{
|
||||||
|
lldebugs << "Encoding new image of format J2C" << llendl;
|
||||||
|
LLPointer<LLImageJ2C> formatted = new LLImageJ2C;
|
||||||
|
LLPointer<LLImageRaw> scaled = new LLImageRaw(
|
||||||
|
previewp->mPreviewImage->getData(),
|
||||||
|
previewp->mPreviewImage->getWidth(),
|
||||||
|
previewp->mPreviewImage->getHeight(),
|
||||||
|
previewp->mPreviewImage->getComponents());
|
||||||
|
|
||||||
|
scaled->biasedScaleToPowerOfTwo(MAX_TEXTURE_SIZE);
|
||||||
|
previewp->setImageScaled(TRUE);
|
||||||
|
if (formatted->encode(scaled, 0.f))
|
||||||
|
{
|
||||||
|
previewp->mDataSize = formatted->getDataSize();
|
||||||
|
formatted->decode(previewp->mPreviewImageEncoded, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// delete any existing image
|
||||||
|
previewp->mFormattedImage = NULL;
|
||||||
|
// now create the new one of the appropriate format.
|
||||||
|
LLFloaterSnapshot::ESnapshotFormat format = previewp->getSnapshotFormat();
|
||||||
|
lldebugs << "Encoding new image of format " << format << llendl;
|
||||||
|
|
||||||
|
switch(format)
|
||||||
|
{
|
||||||
|
case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG:
|
||||||
|
previewp->mFormattedImage = new LLImagePNG();
|
||||||
|
break;
|
||||||
|
case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG:
|
||||||
|
previewp->mFormattedImage = new LLImageJPEG(previewp->mSnapshotQuality);
|
||||||
|
break;
|
||||||
|
case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP:
|
||||||
|
previewp->mFormattedImage = new LLImageBMP();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (previewp->mFormattedImage->encode(previewp->mPreviewImage, 0))
|
||||||
|
{
|
||||||
|
previewp->mDataSize = previewp->mFormattedImage->getDataSize();
|
||||||
|
// special case BMP to copy instead of decode otherwise decode will crash.
|
||||||
|
if(format == LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP)
|
||||||
|
{
|
||||||
|
previewp->mPreviewImageEncoded->copy(previewp->mPreviewImage);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
previewp->mFormattedImage->decode(previewp->mPreviewImageEncoded, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LLPointer<LLImageRaw> scaled = new LLImageRaw(
|
||||||
|
previewp->mPreviewImageEncoded->getData(),
|
||||||
|
previewp->mPreviewImageEncoded->getWidth(),
|
||||||
|
previewp->mPreviewImageEncoded->getHeight(),
|
||||||
|
previewp->mPreviewImageEncoded->getComponents());
|
||||||
|
|
||||||
|
if(!scaled->isBufferInvalid())
|
||||||
|
{
|
||||||
|
// leave original image dimensions, just scale up texture buffer
|
||||||
|
if (previewp->mPreviewImageEncoded->getWidth() > 1024 || previewp->mPreviewImageEncoded->getHeight() > 1024)
|
||||||
|
{
|
||||||
|
// go ahead and shrink image to appropriate power of 2 for display
|
||||||
|
scaled->biasedScaleToPowerOfTwo(1024);
|
||||||
|
previewp->setImageScaled(TRUE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// expand image but keep original image data intact
|
||||||
|
scaled->expandToPowerOfTwo(1024, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
previewp->mViewerImage[previewp->mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE);
|
||||||
|
LLPointer<LLViewerTexture> curr_preview_image = previewp->mViewerImage[previewp->mCurImageIndex];
|
||||||
|
gGL.getTexUnit(0)->bind(curr_preview_image);
|
||||||
|
if (previewp->getSnapshotType() != SNAPSHOT_TEXTURE)
|
||||||
|
{
|
||||||
|
curr_preview_image->setFilteringOption(LLTexUnit::TFO_POINT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curr_preview_image->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
|
||||||
|
}
|
||||||
|
curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP);
|
||||||
|
|
||||||
|
previewp->mSnapshotUpToDate = TRUE;
|
||||||
|
previewp->generateThumbnailImage(TRUE) ;
|
||||||
|
|
||||||
|
previewp->mPosTakenGlobal = gAgentCamera.getCameraPositionGlobal();
|
||||||
|
previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame
|
||||||
|
}
|
||||||
|
}
|
||||||
|
previewp->getWindow()->decBusyCount();
|
||||||
|
// only show fullscreen preview when in freeze frame mode
|
||||||
|
previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame"));
|
||||||
|
previewp->mSnapshotDelayTimer.stop();
|
||||||
|
previewp->mSnapshotActive = FALSE;
|
||||||
|
|
||||||
|
if(!previewp->getThumbnailUpToDate())
|
||||||
|
{
|
||||||
|
previewp->generateThumbnailImage() ;
|
||||||
|
}
|
||||||
|
lldebugs << "done creating snapshot" << llendl;
|
||||||
|
LLFloaterSnapshot::postUpdate();
|
||||||
|
LLFloaterSocial::postUpdate();
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSnapshotLivePreview::setSize(S32 w, S32 h)
|
||||||
|
{
|
||||||
|
lldebugs << "setSize(" << w << ", " << h << ")" << llendl;
|
||||||
|
setWidth(w);
|
||||||
|
setHeight(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSnapshotLivePreview::getSize(S32& w, S32& h) const
|
||||||
|
{
|
||||||
|
w = getWidth();
|
||||||
|
h = getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSnapshotLivePreview::saveTexture()
|
||||||
|
{
|
||||||
|
lldebugs << "saving texture: " << mPreviewImage->getWidth() << "x" << mPreviewImage->getHeight() << llendl;
|
||||||
|
// gen a new uuid for this asset
|
||||||
|
LLTransactionID tid;
|
||||||
|
tid.generate();
|
||||||
|
LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
|
||||||
|
|
||||||
|
LLPointer<LLImageJ2C> formatted = new LLImageJ2C;
|
||||||
|
LLPointer<LLImageRaw> scaled = new LLImageRaw(mPreviewImage->getData(),
|
||||||
|
mPreviewImage->getWidth(),
|
||||||
|
mPreviewImage->getHeight(),
|
||||||
|
mPreviewImage->getComponents());
|
||||||
|
|
||||||
|
scaled->biasedScaleToPowerOfTwo(MAX_TEXTURE_SIZE);
|
||||||
|
lldebugs << "scaled texture to " << scaled->getWidth() << "x" << scaled->getHeight() << llendl;
|
||||||
|
|
||||||
|
if (formatted->encode(scaled, 0.0f))
|
||||||
|
{
|
||||||
|
LLVFile::writeFile(formatted->getData(), formatted->getDataSize(), gVFS, new_asset_id, LLAssetType::AT_TEXTURE);
|
||||||
|
std::string pos_string;
|
||||||
|
LLAgentUI::buildLocationString(pos_string, LLAgentUI::LOCATION_FORMAT_FULL);
|
||||||
|
std::string who_took_it;
|
||||||
|
LLAgentUI::buildFullname(who_took_it);
|
||||||
|
LLAssetStorage::LLStoreAssetCallback callback = NULL;
|
||||||
|
S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
|
||||||
|
void *userdata = NULL;
|
||||||
|
upload_new_resource(tid, // tid
|
||||||
|
LLAssetType::AT_TEXTURE,
|
||||||
|
"Snapshot : " + pos_string,
|
||||||
|
"Taken by " + who_took_it + " at " + pos_string,
|
||||||
|
0,
|
||||||
|
LLFolderType::FT_SNAPSHOT_CATEGORY,
|
||||||
|
LLInventoryType::IT_SNAPSHOT,
|
||||||
|
PERM_ALL, // Note: Snapshots to inventory is a special case of content upload
|
||||||
|
LLFloaterPerms::getGroupPerms(), // that is more permissive than other uploads
|
||||||
|
LLFloaterPerms::getEveryonePerms(),
|
||||||
|
"Snapshot : " + pos_string,
|
||||||
|
callback, expected_upload_cost, userdata);
|
||||||
|
gViewerWindow->playSnapshotAnimAndSound();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LLNotificationsUtil::add("ErrorEncodingSnapshot");
|
||||||
|
llwarns << "Error encoding snapshot" << llendl;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLViewerStats::getInstance()->incStat(LLViewerStats::ST_SNAPSHOT_COUNT );
|
||||||
|
|
||||||
|
mDataSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL LLSnapshotLivePreview::saveLocal()
|
||||||
|
{
|
||||||
|
BOOL success = gViewerWindow->saveImageNumbered(mFormattedImage);
|
||||||
|
|
||||||
|
if(success)
|
||||||
|
{
|
||||||
|
gViewerWindow->playSnapshotAnimAndSound();
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLSnapshotLivePreview::saveWeb()
|
||||||
|
{
|
||||||
|
// *FIX: Will break if the window closes because of CloseSnapshotOnKeep!
|
||||||
|
// Needs to pass on ownership of the image.
|
||||||
|
LLImageJPEG* jpg = dynamic_cast<LLImageJPEG*>(mFormattedImage.get());
|
||||||
|
if(!jpg)
|
||||||
|
{
|
||||||
|
llwarns << "Formatted image not a JPEG" << llendl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLSD metadata;
|
||||||
|
metadata["description"] = getChild<LLLineEditor>("description")->getText();
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
metadata["slurl"] = LLSLURL(name, LLVector3d(x, y, z)).getSLURLString();
|
||||||
|
|
||||||
|
LLWebSharing::instance().shareSnapshot(snapshot, metadata);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
/**
|
||||||
|
* @file llsnapshotlivepreview.h
|
||||||
|
* @brief Header file for llsnapshotlivepreview
|
||||||
|
* @author Gilbert@lindenlab.com
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
|
||||||
|
* Second Life Viewer Source Code
|
||||||
|
* Copyright (C) 2013, Linden Research, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation;
|
||||||
|
* version 2.1 of the License only.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
|
* $/LicenseInfo$
|
||||||
|
*/
|
||||||
|
#ifndef LL_LLSNAPSHOTLIVEPREVIEW_H
|
||||||
|
#define LL_LLSNAPSHOTLIVEPREVIEW_H
|
||||||
|
|
||||||
|
#include "llpanelsnapshot.h"
|
||||||
|
#include "llviewerwindow.h"
|
||||||
|
|
||||||
|
class LLImageJPEG;
|
||||||
|
|
||||||
|
///----------------------------------------------------------------------------
|
||||||
|
/// Class LLSnapshotLivePreview
|
||||||
|
///----------------------------------------------------------------------------
|
||||||
|
class LLSnapshotLivePreview : public LLView
|
||||||
|
{
|
||||||
|
LOG_CLASS(LLSnapshotLivePreview);
|
||||||
|
public:
|
||||||
|
enum ESnapshotType
|
||||||
|
{
|
||||||
|
SNAPSHOT_POSTCARD,
|
||||||
|
SNAPSHOT_TEXTURE,
|
||||||
|
SNAPSHOT_LOCAL,
|
||||||
|
SNAPSHOT_WEB
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Params : public LLInitParam::Block<Params, LLView::Params>
|
||||||
|
{
|
||||||
|
Params()
|
||||||
|
{
|
||||||
|
name = "snapshot_live_preview";
|
||||||
|
mouse_opaque = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
LLSnapshotLivePreview(const LLSnapshotLivePreview::Params& p);
|
||||||
|
~LLSnapshotLivePreview();
|
||||||
|
|
||||||
|
/*virtual*/ void draw();
|
||||||
|
/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent);
|
||||||
|
|
||||||
|
void setSize(S32 w, S32 h);
|
||||||
|
void setWidth(S32 w) { mWidth[mCurImageIndex] = w; }
|
||||||
|
void setHeight(S32 h) { mHeight[mCurImageIndex] = h; }
|
||||||
|
void getSize(S32& w, S32& h) const;
|
||||||
|
S32 getWidth() const { return mWidth[mCurImageIndex]; }
|
||||||
|
S32 getHeight() const { return mHeight[mCurImageIndex]; }
|
||||||
|
S32 getDataSize() const { return mDataSize; }
|
||||||
|
void setMaxImageSize(S32 size) ;
|
||||||
|
S32 getMaxImageSize() {return mMaxImageSize ;}
|
||||||
|
|
||||||
|
ESnapshotType getSnapshotType() const { return mSnapshotType; }
|
||||||
|
LLFloaterSnapshot::ESnapshotFormat getSnapshotFormat() const { return mSnapshotFormat; }
|
||||||
|
BOOL getSnapshotUpToDate() const { return mSnapshotUpToDate; }
|
||||||
|
BOOL isSnapshotActive() { return mSnapshotActive; }
|
||||||
|
LLViewerTexture* getThumbnailImage() const { return mThumbnailImage ; }
|
||||||
|
S32 getThumbnailWidth() const { return mThumbnailWidth ; }
|
||||||
|
S32 getThumbnailHeight() const { return mThumbnailHeight ; }
|
||||||
|
BOOL getThumbnailLock() const { return mThumbnailUpdateLock ; }
|
||||||
|
BOOL getThumbnailUpToDate() const { return mThumbnailUpToDate ;}
|
||||||
|
LLViewerTexture* getCurrentImage();
|
||||||
|
F32 getImageAspect();
|
||||||
|
F32 getAspect() ;
|
||||||
|
const LLRect& getImageRect() const { return mImageRect[mCurImageIndex]; }
|
||||||
|
BOOL isImageScaled() const { return mImageScaled[mCurImageIndex]; }
|
||||||
|
void setImageScaled(BOOL scaled) { mImageScaled[mCurImageIndex] = scaled; }
|
||||||
|
const LLVector3d& getPosTakenGlobal() const { return mPosTakenGlobal; }
|
||||||
|
|
||||||
|
void setSnapshotType(ESnapshotType type) { mSnapshotType = type; }
|
||||||
|
void setSnapshotFormat(LLFloaterSnapshot::ESnapshotFormat type) { mSnapshotFormat = type; }
|
||||||
|
void setSnapshotQuality(S32 quality);
|
||||||
|
void setSnapshotBufferType(LLViewerWindow::ESnapshotType type) { mSnapshotBufferType = type; }
|
||||||
|
void updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail = FALSE, F32 delay = 0.f);
|
||||||
|
void saveWeb();
|
||||||
|
void saveTexture();
|
||||||
|
BOOL saveLocal();
|
||||||
|
|
||||||
|
LLPointer<LLImageFormatted> getFormattedImage() const { return mFormattedImage; }
|
||||||
|
LLPointer<LLImageRaw> getEncodedImage() const { return mPreviewImageEncoded; }
|
||||||
|
|
||||||
|
/// Sets size of preview thumbnail image and thhe surrounding rect.
|
||||||
|
void setThumbnailPlaceholderRect(const LLRect& rect) {mThumbnailPlaceholderRect = rect; }
|
||||||
|
BOOL setThumbnailImageSize() ;
|
||||||
|
void generateThumbnailImage(BOOL force_update = FALSE) ;
|
||||||
|
void resetThumbnailImage() { mThumbnailImage = NULL ; }
|
||||||
|
void drawPreviewRect(S32 offset_x, S32 offset_y) ;
|
||||||
|
|
||||||
|
// Returns TRUE when snapshot generated, FALSE otherwise.
|
||||||
|
static BOOL onIdle( void* snapshot_preview );
|
||||||
|
|
||||||
|
// callback for region name resolve
|
||||||
|
void regionNameCallback(LLImageJPEG* snapshot, LLSD& metadata, const std::string& name, S32 x, S32 y, S32 z);
|
||||||
|
|
||||||
|
private:
|
||||||
|
LLColor4 mColor;
|
||||||
|
LLPointer<LLViewerTexture> mViewerImage[2]; //used to represent the scene when the frame is frozen.
|
||||||
|
LLRect mImageRect[2];
|
||||||
|
S32 mWidth[2];
|
||||||
|
S32 mHeight[2];
|
||||||
|
BOOL mImageScaled[2];
|
||||||
|
S32 mMaxImageSize ;
|
||||||
|
|
||||||
|
//thumbnail image
|
||||||
|
LLPointer<LLViewerTexture> mThumbnailImage ;
|
||||||
|
S32 mThumbnailWidth ;
|
||||||
|
S32 mThumbnailHeight ;
|
||||||
|
LLRect mPreviewRect ;
|
||||||
|
BOOL mThumbnailUpdateLock ;
|
||||||
|
BOOL mThumbnailUpToDate ;
|
||||||
|
LLRect mThumbnailPlaceholderRect;
|
||||||
|
|
||||||
|
S32 mCurImageIndex;
|
||||||
|
LLPointer<LLImageRaw> mPreviewImage;
|
||||||
|
LLPointer<LLImageRaw> mPreviewImageEncoded;
|
||||||
|
LLPointer<LLImageFormatted> mFormattedImage;
|
||||||
|
LLFrameTimer mSnapshotDelayTimer;
|
||||||
|
S32 mShineCountdown;
|
||||||
|
LLFrameTimer mShineAnimTimer;
|
||||||
|
F32 mFlashAlpha;
|
||||||
|
BOOL mNeedsFlash;
|
||||||
|
LLVector3d mPosTakenGlobal;
|
||||||
|
S32 mSnapshotQuality;
|
||||||
|
S32 mDataSize;
|
||||||
|
ESnapshotType mSnapshotType;
|
||||||
|
LLFloaterSnapshot::ESnapshotFormat mSnapshotFormat;
|
||||||
|
BOOL mSnapshotUpToDate;
|
||||||
|
LLFrameTimer mFallAnimTimer;
|
||||||
|
LLVector3 mCameraPos;
|
||||||
|
LLQuaternion mCameraRot;
|
||||||
|
BOOL mSnapshotActive;
|
||||||
|
LLViewerWindow::ESnapshotType mSnapshotBufferType;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static std::set<LLSnapshotLivePreview*> sList;
|
||||||
|
BOOL mKeepAspectRatio ;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LL_LLSNAPSHOTLIVEPREVIEW_H
|
||||||
|
|
||||||
|
|
@ -118,6 +118,11 @@ void LLSysWellWindow::removeItemByID(const LLUUID& id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LLPanel * LLSysWellWindow::findItemByID(const LLUUID& id)
|
||||||
|
{
|
||||||
|
return mMessageList->getItemByValue(id);
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------
|
||||||
//---------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------
|
||||||
void LLSysWellWindow::initChannel()
|
void LLSysWellWindow::initChannel()
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ public:
|
||||||
|
|
||||||
// Operating with items
|
// Operating with items
|
||||||
void removeItemByID(const LLUUID& id);
|
void removeItemByID(const LLUUID& id);
|
||||||
|
LLPanel * findItemByID(const LLUUID& id);
|
||||||
|
|
||||||
// Operating with outfit
|
// Operating with outfit
|
||||||
virtual void setVisible(BOOL visible);
|
virtual void setVisible(BOOL visible);
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) : LLToastPanel(p.notif
|
||||||
|
|
||||||
if(!mIsGroupMsg)
|
if(!mIsGroupMsg)
|
||||||
{
|
{
|
||||||
mAvatarName->setValue(p.from);
|
mAvatarName->setValue(p.from);
|
||||||
}
|
}
|
||||||
mTime->setValue(p.time);
|
mTime->setValue(p.time);
|
||||||
mSessionID = p.session_id;
|
mSessionID = p.session_id;
|
||||||
|
|
@ -164,7 +164,7 @@ void LLToastIMPanel::spawnNameToolTip()
|
||||||
params.background_visible(false);
|
params.background_visible(false);
|
||||||
if(!mIsGroupMsg)
|
if(!mIsGroupMsg)
|
||||||
{
|
{
|
||||||
params.click_callback(boost::bind(&LLFloaterReg::showInstance, "inspect_avatar", LLSD().with("avatar_id", mAvatarID), FALSE));
|
params.click_callback(boost::bind(&LLFloaterReg::showInstance, "inspect_avatar", LLSD().with("avatar_id", mAvatarID), FALSE));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -103,22 +103,29 @@ LLSD LLURLHistory::getURLHistory(const std::string& collection)
|
||||||
// static
|
// static
|
||||||
void LLURLHistory::addURL(const std::string& collection, const std::string& url)
|
void LLURLHistory::addURL(const std::string& collection, const std::string& url)
|
||||||
{
|
{
|
||||||
if(! url.empty())
|
if(!url.empty())
|
||||||
{
|
{
|
||||||
sHistorySD[collection].insert(0, url);
|
LLURI u(url);
|
||||||
|
std::string simplified_url = u.scheme() + "://" + u.authority() + u.path();
|
||||||
|
sHistorySD[collection].insert(0, simplified_url);
|
||||||
LLURLHistory::limitSize(collection);
|
LLURLHistory::limitSize(collection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// static
|
// static
|
||||||
void LLURLHistory::removeURL(const std::string& collection, const std::string& url)
|
void LLURLHistory::removeURL(const std::string& collection, const std::string& url)
|
||||||
{
|
{
|
||||||
for(int index = 0; index < sHistorySD[collection].size(); index++)
|
if(!url.empty())
|
||||||
{
|
{
|
||||||
if(sHistorySD[collection].get(index).asString() == url)
|
LLURI u(url);
|
||||||
{
|
std::string simplified_url = u.scheme() + "://" + u.authority() + u.path();
|
||||||
sHistorySD[collection].erase(index);
|
for(int index = 0; index < sHistorySD[collection].size(); index++)
|
||||||
}
|
{
|
||||||
}
|
if(sHistorySD[collection].get(index).asString() == simplified_url)
|
||||||
|
{
|
||||||
|
sHistorySD[collection].erase(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,7 @@
|
||||||
#include "llfloatersettingsdebug.h"
|
#include "llfloatersettingsdebug.h"
|
||||||
#include "llfloatersidepanelcontainer.h"
|
#include "llfloatersidepanelcontainer.h"
|
||||||
#include "llfloatersnapshot.h"
|
#include "llfloatersnapshot.h"
|
||||||
|
#include "llfloatersocial.h"
|
||||||
#include "llfloatersounddevices.h"
|
#include "llfloatersounddevices.h"
|
||||||
#include "llfloaterspellchecksettings.h"
|
#include "llfloaterspellchecksettings.h"
|
||||||
#include "llfloatertelehub.h"
|
#include "llfloatertelehub.h"
|
||||||
|
|
@ -303,6 +304,7 @@ void LLViewerFloaterReg::registerFloaters()
|
||||||
LLFloaterReg::add("sell_land", "floater_sell_land.xml", &LLFloaterSellLand::buildFloater);
|
LLFloaterReg::add("sell_land", "floater_sell_land.xml", &LLFloaterSellLand::buildFloater);
|
||||||
LLFloaterReg::add("settings_debug", "floater_settings_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSettingsDebug>);
|
LLFloaterReg::add("settings_debug", "floater_settings_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSettingsDebug>);
|
||||||
LLFloaterReg::add("sound_devices", "floater_sound_devices.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundDevices>);
|
LLFloaterReg::add("sound_devices", "floater_sound_devices.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundDevices>);
|
||||||
|
LLFloaterReg::add("social", "floater_social.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSocial>);
|
||||||
LLFloaterReg::add("stats", "floater_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloater>);
|
LLFloaterReg::add("stats", "floater_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloater>);
|
||||||
LLFloaterReg::add("start_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRunQueue>);
|
LLFloaterReg::add("start_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRunQueue>);
|
||||||
LLFloaterReg::add("stop_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotRunQueue>);
|
LLFloaterReg::add("stop_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotRunQueue>);
|
||||||
|
|
@ -311,7 +313,7 @@ void LLViewerFloaterReg::registerFloaters()
|
||||||
LLFloaterReg::add("my_profile", "floater_my_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create);
|
LLFloaterReg::add("my_profile", "floater_my_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create);
|
||||||
LLFloaterReg::add("profile", "floater_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create);
|
LLFloaterReg::add("profile", "floater_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create);
|
||||||
LLFloaterReg::add("how_to", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create);
|
LLFloaterReg::add("how_to", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create);
|
||||||
|
LLFloaterReg::add("fbc_web", "floater_fbc_web.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create);
|
||||||
|
|
||||||
LLFloaterUIPreviewUtil::registerFloater();
|
LLFloaterUIPreviewUtil::registerFloater();
|
||||||
LLFloaterReg::add("upload_anim_bvh", "floater_animation_bvh_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBvhPreview>, "upload");
|
LLFloaterReg::add("upload_anim_bvh", "floater_animation_bvh_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBvhPreview>, "upload");
|
||||||
|
|
|
||||||
|
|
@ -687,7 +687,10 @@ BOOL LLViewerKeyboard::handleKey(KEY translated_key, MASK translated_mask, BOOL
|
||||||
{
|
{
|
||||||
// it is sufficient to set this value once per call to handlekey
|
// it is sufficient to set this value once per call to handlekey
|
||||||
// without clearing it, as it is only used in the subsequent call to scanKey
|
// without clearing it, as it is only used in the subsequent call to scanKey
|
||||||
mKeyHandledByUI[translated_key] = gViewerWindow->handleKey(translated_key, translated_mask);
|
mKeyHandledByUI[translated_key] = gViewerWindow->handleKey(translated_key, translated_mask);
|
||||||
|
// mKeyHandledByUI is not what you think ... this indicates whether the UI has handled this keypress yet (any keypress)
|
||||||
|
// NOT whether some UI shortcut wishes to handle the keypress
|
||||||
|
|
||||||
}
|
}
|
||||||
return mKeyHandledByUI[translated_key];
|
return mKeyHandledByUI[translated_key];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2000,7 +2000,12 @@ void LLViewerMediaImpl::loadURI()
|
||||||
"<>#%"
|
"<>#%"
|
||||||
";/?:@&=",
|
";/?:@&=",
|
||||||
false);
|
false);
|
||||||
llinfos << "Asking media source to load URI: " << uri << llendl;
|
{
|
||||||
|
// Do not log the query parts
|
||||||
|
LLURI u(uri);
|
||||||
|
std::string sanitized_uri = (u.query().empty() ? uri : u.scheme() + "://" + u.authority() + u.path());
|
||||||
|
llinfos << "Asking media source to load URI: " << sanitized_uri << llendl;
|
||||||
|
}
|
||||||
|
|
||||||
mMediaSource->loadURI( uri );
|
mMediaSource->loadURI( uri );
|
||||||
|
|
||||||
|
|
@ -2567,7 +2572,12 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi
|
||||||
if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
|
if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
|
||||||
{
|
{
|
||||||
// Helpful to have media urls in log file. Shouldn't be spammy.
|
// Helpful to have media urls in log file. Shouldn't be spammy.
|
||||||
llinfos << "NOT LOADING media id= " << mTextureId << " url=" << url << " mime_type=" << mime_type << llendl;
|
{
|
||||||
|
// Do not log the query parts
|
||||||
|
LLURI u(url);
|
||||||
|
std::string sanitized_url = (u.query().empty() ? url : u.scheme() + "://" + u.authority() + u.path());
|
||||||
|
llinfos << "NOT LOADING media id= " << mTextureId << " url=" << sanitized_url << ", mime_type=" << mime_type << llendl;
|
||||||
|
}
|
||||||
|
|
||||||
// This impl should not be loaded at this time.
|
// This impl should not be loaded at this time.
|
||||||
LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL;
|
LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL;
|
||||||
|
|
@ -2582,7 +2592,12 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi
|
||||||
void LLViewerMediaImpl::navigateInternal()
|
void LLViewerMediaImpl::navigateInternal()
|
||||||
{
|
{
|
||||||
// Helpful to have media urls in log file. Shouldn't be spammy.
|
// Helpful to have media urls in log file. Shouldn't be spammy.
|
||||||
llinfos << "media id= " << mTextureId << " url=" << mMediaURL << " mime_type=" << mMimeType << llendl;
|
{
|
||||||
|
// Do not log the query parts
|
||||||
|
LLURI u(mMediaURL);
|
||||||
|
std::string sanitized_url = (u.query().empty() ? mMediaURL : u.scheme() + "://" + u.authority() + u.path());
|
||||||
|
llinfos << "media id= " << mTextureId << " url=" << sanitized_url << ", mime_type=" << mMimeType << llendl;
|
||||||
|
}
|
||||||
|
|
||||||
if(mNavigateSuspended)
|
if(mNavigateSuspended)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -40,11 +40,13 @@
|
||||||
#include "llinventorypanel.h"
|
#include "llinventorypanel.h"
|
||||||
#include "llnotifications.h"
|
#include "llnotifications.h"
|
||||||
#include "llnotificationsutil.h"
|
#include "llnotificationsutil.h"
|
||||||
|
#include "llviewereventrecorder.h"
|
||||||
|
|
||||||
// newview includes
|
// newview includes
|
||||||
#include "llagent.h"
|
#include "llagent.h"
|
||||||
#include "llagentaccess.h"
|
#include "llagentaccess.h"
|
||||||
#include "llagentcamera.h"
|
#include "llagentcamera.h"
|
||||||
|
#include "llagentui.h"
|
||||||
#include "llagentwearables.h"
|
#include "llagentwearables.h"
|
||||||
#include "llagentpilot.h"
|
#include "llagentpilot.h"
|
||||||
#include "llcompilequeue.h"
|
#include "llcompilequeue.h"
|
||||||
|
|
@ -52,6 +54,7 @@
|
||||||
#include "lldaycyclemanager.h"
|
#include "lldaycyclemanager.h"
|
||||||
#include "lldebugview.h"
|
#include "lldebugview.h"
|
||||||
#include "llenvmanager.h"
|
#include "llenvmanager.h"
|
||||||
|
#include "llfacebookconnect.h"
|
||||||
#include "llfilepicker.h"
|
#include "llfilepicker.h"
|
||||||
#include "llfirstuse.h"
|
#include "llfirstuse.h"
|
||||||
#include "llfloaterbuy.h"
|
#include "llfloaterbuy.h"
|
||||||
|
|
@ -1952,6 +1955,43 @@ class LLAdvancedDropPacket : public view_listener_t
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// EVENT Recorder //
|
||||||
|
///////////////////
|
||||||
|
|
||||||
|
|
||||||
|
class LLAdvancedViewerEventRecorder : public view_listener_t
|
||||||
|
{
|
||||||
|
bool handleEvent(const LLSD& userdata)
|
||||||
|
{
|
||||||
|
std::string command = userdata.asString();
|
||||||
|
if ("start playback" == command)
|
||||||
|
{
|
||||||
|
llinfos << "Event Playback starting" << llendl;
|
||||||
|
LLViewerEventRecorder::instance().playbackRecording();
|
||||||
|
llinfos << "Event Playback completed" << llendl;
|
||||||
|
}
|
||||||
|
else if ("stop playback" == command)
|
||||||
|
{
|
||||||
|
// Future
|
||||||
|
}
|
||||||
|
else if ("start recording" == command)
|
||||||
|
{
|
||||||
|
LLViewerEventRecorder::instance().setEventLoggingOn();
|
||||||
|
llinfos << "Event recording started" << llendl;
|
||||||
|
}
|
||||||
|
else if ("stop recording" == command)
|
||||||
|
{
|
||||||
|
LLViewerEventRecorder::instance().setEventLoggingOff();
|
||||||
|
llinfos << "Event recording stopped" << llendl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////
|
/////////////////
|
||||||
// AGENT PILOT //
|
// AGENT PILOT //
|
||||||
|
|
@ -8420,6 +8460,8 @@ void initialize_menus()
|
||||||
// Don't prepend MenuName.Foo because these can be used in any menu.
|
// Don't prepend MenuName.Foo because these can be used in any menu.
|
||||||
enable.add("IsGodCustomerService", boost::bind(&is_god_customer_service));
|
enable.add("IsGodCustomerService", boost::bind(&is_god_customer_service));
|
||||||
|
|
||||||
|
enable.add("displayViewerEventRecorderMenuItems",boost::bind(&LLViewerEventRecorder::displayViewerEventRecorderMenuItems,&LLViewerEventRecorder::instance()));
|
||||||
|
|
||||||
view_listener_t::addEnable(new LLUploadCostCalculator(), "Upload.CalculateCosts");
|
view_listener_t::addEnable(new LLUploadCostCalculator(), "Upload.CalculateCosts");
|
||||||
|
|
||||||
enable.add("Conversation.IsConversationLoggingAllowed", boost::bind(&LLFloaterIMContainer::isConversationLoggingAllowed));
|
enable.add("Conversation.IsConversationLoggingAllowed", boost::bind(&LLFloaterIMContainer::isConversationLoggingAllowed));
|
||||||
|
|
@ -8678,6 +8720,7 @@ void initialize_menus()
|
||||||
view_listener_t::addMenu(new LLAdvancedAgentPilot(), "Advanced.AgentPilot");
|
view_listener_t::addMenu(new LLAdvancedAgentPilot(), "Advanced.AgentPilot");
|
||||||
view_listener_t::addMenu(new LLAdvancedToggleAgentPilotLoop(), "Advanced.ToggleAgentPilotLoop");
|
view_listener_t::addMenu(new LLAdvancedToggleAgentPilotLoop(), "Advanced.ToggleAgentPilotLoop");
|
||||||
view_listener_t::addMenu(new LLAdvancedCheckAgentPilotLoop(), "Advanced.CheckAgentPilotLoop");
|
view_listener_t::addMenu(new LLAdvancedCheckAgentPilotLoop(), "Advanced.CheckAgentPilotLoop");
|
||||||
|
view_listener_t::addMenu(new LLAdvancedViewerEventRecorder(), "Advanced.EventRecorder");
|
||||||
|
|
||||||
// Advanced > Debugging
|
// Advanced > Debugging
|
||||||
view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint");
|
view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint");
|
||||||
|
|
|
||||||
|
|
@ -2221,7 +2221,7 @@ static std::string clean_name_from_im(const std::string& name, EInstantMessage t
|
||||||
case IM_LURE_ACCEPTED:
|
case IM_LURE_ACCEPTED:
|
||||||
case IM_LURE_DECLINED:
|
case IM_LURE_DECLINED:
|
||||||
case IM_GODLIKE_LURE_USER:
|
case IM_GODLIKE_LURE_USER:
|
||||||
case IM_YET_TO_BE_USED:
|
case IM_TELEPORT_REQUEST:
|
||||||
case IM_GROUP_ELECTION_DEPRECATED:
|
case IM_GROUP_ELECTION_DEPRECATED:
|
||||||
//IM_GOTO_URL
|
//IM_GOTO_URL
|
||||||
//IM_FROM_TASK_AS_ALERT
|
//IM_FROM_TASK_AS_ALERT
|
||||||
|
|
@ -2989,6 +2989,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IM_LURE_USER:
|
case IM_LURE_USER:
|
||||||
|
case IM_TELEPORT_REQUEST:
|
||||||
{
|
{
|
||||||
if (is_muted)
|
if (is_muted)
|
||||||
{
|
{
|
||||||
|
|
@ -3011,7 +3012,8 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
|
||||||
bool canUserAccessDstRegion = true;
|
bool canUserAccessDstRegion = true;
|
||||||
bool doesUserRequireMaturityIncrease = false;
|
bool doesUserRequireMaturityIncrease = false;
|
||||||
|
|
||||||
if (parse_lure_bucket(region_info, region_handle, pos, look_at, region_access))
|
// Do not parse the (empty) lure bucket for TELEPORT_REQUEST
|
||||||
|
if (IM_TELEPORT_REQUEST != dialog && parse_lure_bucket(region_info, region_handle, pos, look_at, region_access))
|
||||||
{
|
{
|
||||||
region_access_str = LLViewerRegion::accessToString(region_access);
|
region_access_str = LLViewerRegion::accessToString(region_access);
|
||||||
region_access_icn = LLViewerRegion::getAccessIcon(region_access);
|
region_access_icn = LLViewerRegion::getAccessIcon(region_access);
|
||||||
|
|
@ -3083,12 +3085,22 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LLNotification::Params params("TeleportOffered");
|
LLNotification::Params params;
|
||||||
|
if (IM_LURE_USER == dialog)
|
||||||
|
{
|
||||||
|
params.name = "TeleportOffered";
|
||||||
|
params.functor.name = "TeleportOffered";
|
||||||
|
}
|
||||||
|
else if (IM_TELEPORT_REQUEST == dialog)
|
||||||
|
{
|
||||||
|
params.name = "TeleportRequest";
|
||||||
|
params.functor.name = "TeleportRequest";
|
||||||
|
}
|
||||||
|
|
||||||
params.substitutions = args;
|
params.substitutions = args;
|
||||||
params.payload = payload;
|
params.payload = payload;
|
||||||
LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false);
|
LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -6866,6 +6878,51 @@ void send_group_notice(const LLUUID& group_id,
|
||||||
bin_bucket_size);
|
bin_bucket_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void send_lures(const LLSD& notification, const LLSD& response)
|
||||||
|
{
|
||||||
|
std::string text = response["message"].asString();
|
||||||
|
LLSLURL slurl;
|
||||||
|
LLAgentUI::buildSLURL(slurl);
|
||||||
|
text.append("\r\n").append(slurl.getSLURLString());
|
||||||
|
|
||||||
|
LLMessageSystem* msg = gMessageSystem;
|
||||||
|
msg->newMessageFast(_PREHASH_StartLure);
|
||||||
|
msg->nextBlockFast(_PREHASH_AgentData);
|
||||||
|
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
||||||
|
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
||||||
|
msg->nextBlockFast(_PREHASH_Info);
|
||||||
|
msg->addU8Fast(_PREHASH_LureType, (U8)0); // sim will fill this in.
|
||||||
|
msg->addStringFast(_PREHASH_Message, text);
|
||||||
|
for(LLSD::array_const_iterator it = notification["payload"]["ids"].beginArray();
|
||||||
|
it != notification["payload"]["ids"].endArray();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
LLUUID target_id = it->asUUID();
|
||||||
|
|
||||||
|
msg->nextBlockFast(_PREHASH_TargetData);
|
||||||
|
msg->addUUIDFast(_PREHASH_TargetID, target_id);
|
||||||
|
|
||||||
|
// Record the offer.
|
||||||
|
{
|
||||||
|
std::string target_name;
|
||||||
|
gCacheName->getFullName(target_id, target_name); // for im log filenames
|
||||||
|
LLSD args;
|
||||||
|
args["TO_NAME"] = LLSLURL("agent", target_id, "displayname").getSLURLString();;
|
||||||
|
|
||||||
|
LLSD payload;
|
||||||
|
|
||||||
|
//*TODO please rewrite all keys to the same case, lower or upper
|
||||||
|
payload["from_id"] = target_id;
|
||||||
|
payload["SUPPRESS_TOAST"] = true;
|
||||||
|
LLNotificationsUtil::add("TeleportOfferSent", args, payload);
|
||||||
|
|
||||||
|
// Add the recepient to the recent people list.
|
||||||
|
LLRecentPeople::instance().add(target_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gAgent.sendReliableMessage();
|
||||||
|
}
|
||||||
|
|
||||||
bool handle_lure_callback(const LLSD& notification, const LLSD& response)
|
bool handle_lure_callback(const LLSD& notification, const LLSD& response)
|
||||||
{
|
{
|
||||||
static const unsigned OFFER_RECIPIENT_LIMIT = 250;
|
static const unsigned OFFER_RECIPIENT_LIMIT = 250;
|
||||||
|
|
@ -6879,50 +6936,12 @@ bool handle_lure_callback(const LLSD& notification, const LLSD& response)
|
||||||
LLNotificationsUtil::add("TooManyTeleportOffers", args);
|
LLNotificationsUtil::add("TooManyTeleportOffers", args);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string text = response["message"].asString();
|
|
||||||
LLSLURL slurl;
|
|
||||||
LLAgentUI::buildSLURL(slurl);
|
|
||||||
text.append("\r\n").append(slurl.getSLURLString());
|
|
||||||
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
||||||
|
|
||||||
if(0 == option)
|
if(0 == option)
|
||||||
{
|
{
|
||||||
LLMessageSystem* msg = gMessageSystem;
|
send_lures(notification, response);
|
||||||
msg->newMessageFast(_PREHASH_StartLure);
|
|
||||||
msg->nextBlockFast(_PREHASH_AgentData);
|
|
||||||
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
|
||||||
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
|
||||||
msg->nextBlockFast(_PREHASH_Info);
|
|
||||||
msg->addU8Fast(_PREHASH_LureType, (U8)0); // sim will fill this in.
|
|
||||||
msg->addStringFast(_PREHASH_Message, text);
|
|
||||||
for(LLSD::array_const_iterator it = notification["payload"]["ids"].beginArray();
|
|
||||||
it != notification["payload"]["ids"].endArray();
|
|
||||||
++it)
|
|
||||||
{
|
|
||||||
LLUUID target_id = it->asUUID();
|
|
||||||
|
|
||||||
msg->nextBlockFast(_PREHASH_TargetData);
|
|
||||||
msg->addUUIDFast(_PREHASH_TargetID, target_id);
|
|
||||||
|
|
||||||
// Record the offer.
|
|
||||||
{
|
|
||||||
std::string target_name;
|
|
||||||
gCacheName->getFullName(target_id, target_name); // for im log filenames
|
|
||||||
LLSD args;
|
|
||||||
args["TO_NAME"] = LLSLURL("agent", target_id, "displayname").getSLURLString();;
|
|
||||||
|
|
||||||
LLSD payload;
|
|
||||||
|
|
||||||
//*TODO please rewrite all keys to the same case, lower or upper
|
|
||||||
payload["from_id"] = target_id;
|
|
||||||
LLNotificationsUtil::add("TeleportOfferSent", args, payload);
|
|
||||||
|
|
||||||
// Add the recepient to the recent people list.
|
|
||||||
LLRecentPeople::instance().add(target_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gAgent.sendReliableMessage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -6962,6 +6981,58 @@ void handle_lure(const uuid_vec_t& ids)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool teleport_request_callback(const LLSD& notification, const LLSD& response)
|
||||||
|
{
|
||||||
|
LLUUID from_id = notification["payload"]["from_id"].asUUID();
|
||||||
|
if(from_id.isNull())
|
||||||
|
{
|
||||||
|
llwarns << "from_id is NULL" << llendl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string from_name;
|
||||||
|
gCacheName->getFullName(from_id, from_name);
|
||||||
|
|
||||||
|
if(LLMuteList::getInstance()->isMuted(from_id) && !LLMuteList::getInstance()->isLinden(from_name))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
S32 option = 0;
|
||||||
|
if (response.isInteger())
|
||||||
|
{
|
||||||
|
option = response.asInteger();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
option = LLNotificationsUtil::getSelectedOption(notification, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(option)
|
||||||
|
{
|
||||||
|
// Yes
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
LLSD dummy_notification;
|
||||||
|
dummy_notification["payload"]["ids"][0] = from_id;
|
||||||
|
|
||||||
|
LLSD dummy_response;
|
||||||
|
dummy_response["message"] = response["message"];
|
||||||
|
|
||||||
|
send_lures(dummy_notification, dummy_response);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// No
|
||||||
|
case 1:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static LLNotificationFunctorRegistration teleport_request_callback_reg("TeleportRequest", teleport_request_callback);
|
||||||
|
|
||||||
void send_improved_im(const LLUUID& to_id,
|
void send_improved_im(const LLUUID& to_id,
|
||||||
const std::string& name,
|
const std::string& name,
|
||||||
|
|
|
||||||
|
|
@ -5879,6 +5879,13 @@ void LLViewerObject::resetChildrenPosition(const LLVector3& offset, BOOL simplif
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// virtual
|
||||||
|
BOOL LLViewerObject::isTempAttachment() const
|
||||||
|
{
|
||||||
|
return (mID.notNull() && (mID == mAttachmentItemID));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const LLUUID &LLViewerObject::getAttachmentItemID() const
|
const LLUUID &LLViewerObject::getAttachmentItemID() const
|
||||||
{
|
{
|
||||||
return mAttachmentItemID;
|
return mAttachmentItemID;
|
||||||
|
|
|
||||||
|
|
@ -171,6 +171,8 @@ public:
|
||||||
virtual BOOL isAttachment() const { return FALSE; }
|
virtual BOOL isAttachment() const { return FALSE; }
|
||||||
virtual LLVOAvatar* getAvatar() const; //get the avatar this object is attached to, or NULL if object is not an attachment
|
virtual LLVOAvatar* getAvatar() const; //get the avatar this object is attached to, or NULL if object is not an attachment
|
||||||
virtual BOOL isHUDAttachment() const { return FALSE; }
|
virtual BOOL isHUDAttachment() const { return FALSE; }
|
||||||
|
virtual BOOL isTempAttachment() const;
|
||||||
|
|
||||||
virtual void updateRadius() {};
|
virtual void updateRadius() {};
|
||||||
virtual F32 getVObjRadius() const; // default implemenation is mDrawable->getRadius()
|
virtual F32 getVObjRadius() const; // default implemenation is mDrawable->getRadius()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -954,15 +954,17 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
|
||||||
objectp = *idle_iter;
|
objectp = *idle_iter;
|
||||||
llassert(objectp->isActive());
|
llassert(objectp->isActive());
|
||||||
objectp->idleUpdate(agent, world, frame_time);
|
objectp->idleUpdate(agent, world, frame_time);
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//update flexible objects
|
//update flexible objects
|
||||||
LLVolumeImplFlexible::updateClass();
|
LLVolumeImplFlexible::updateClass();
|
||||||
|
|
||||||
//update animated textures
|
//update animated textures
|
||||||
LLViewerTextureAnim::updateClass();
|
if (gAnimateTextures)
|
||||||
}
|
{
|
||||||
|
LLViewerTextureAnim::updateClass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1587,6 +1587,8 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
|
||||||
capabilityNames.append("EnvironmentSettings");
|
capabilityNames.append("EnvironmentSettings");
|
||||||
capabilityNames.append("EstateChangeInfo");
|
capabilityNames.append("EstateChangeInfo");
|
||||||
capabilityNames.append("EventQueueGet");
|
capabilityNames.append("EventQueueGet");
|
||||||
|
capabilityNames.append("FacebookConnect");
|
||||||
|
//capabilityNames.append("FacebookRedirect");
|
||||||
|
|
||||||
if (gSavedSettings.getBOOL("UseHTTPInventory"))
|
if (gSavedSettings.getBOOL("UseHTTPInventory"))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,8 @@
|
||||||
#include "llagentui.h"
|
#include "llagentui.h"
|
||||||
#include "llwearablelist.h"
|
#include "llwearablelist.h"
|
||||||
|
|
||||||
|
#include "llviewereventrecorder.h"
|
||||||
|
|
||||||
#include "llnotifications.h"
|
#include "llnotifications.h"
|
||||||
#include "llnotificationsutil.h"
|
#include "llnotificationsutil.h"
|
||||||
#include "llnotificationmanager.h"
|
#include "llnotificationmanager.h"
|
||||||
|
|
@ -954,27 +956,18 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK
|
||||||
{
|
{
|
||||||
llinfos << buttonname << " Mouse " << buttonstatestr << " handled by captor " << mouse_captor->getName() << llendl;
|
llinfos << buttonname << " Mouse " << buttonstatestr << " handled by captor " << mouse_captor->getName() << llendl;
|
||||||
}
|
}
|
||||||
return mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Topmost view gets a chance before the hierarchy
|
BOOL r = mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down);
|
||||||
//LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
|
if (r) {
|
||||||
//if (top_ctrl)
|
|
||||||
//{
|
lldebugs << "LLViewerWindow::handleAnyMouseClick viewer with mousecaptor calling updatemouseeventinfo - local_x|global x "<< local_x << " " << x << "local/global y " << local_y << " " << y << llendl;
|
||||||
// S32 local_x, local_y;
|
|
||||||
// top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
|
LLViewerEventRecorder::instance().setMouseGlobalCoords(x,y);
|
||||||
// if (top_ctrl->pointInView(local_x, local_y))
|
LLViewerEventRecorder::instance().logMouseEvent(std::string(buttonstatestr),std::string(buttonname));
|
||||||
// {
|
|
||||||
// return top_ctrl->handleAnyMouseClick(local_x, local_y, mask, clicktype, down) ;
|
}
|
||||||
// }
|
return r;
|
||||||
// else
|
}
|
||||||
// {
|
|
||||||
// if (down)
|
|
||||||
// {
|
|
||||||
// gFocusMgr.setTopCtrl(NULL);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
// Mark the click as handled and return if we aren't within the root view to avoid spurious bugs
|
// Mark the click as handled and return if we aren't within the root view to avoid spurious bugs
|
||||||
if( !mRootView->pointInView(x, y) )
|
if( !mRootView->pointInView(x, y) )
|
||||||
|
|
@ -982,27 +975,44 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
// Give the UI views a chance to process the click
|
// Give the UI views a chance to process the click
|
||||||
if( mRootView->handleAnyMouseClick(x, y, mask, clicktype, down) )
|
|
||||||
|
BOOL r= mRootView->handleAnyMouseClick(x, y, mask, clicktype, down) ;
|
||||||
|
if (r)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
lldebugs << "LLViewerWindow::handleAnyMouseClick calling updatemouseeventinfo - global x "<< " " << x << "global y " << y << "buttonstate: " << buttonstatestr << " buttonname " << buttonname << llendl;
|
||||||
|
|
||||||
|
LLViewerEventRecorder::instance().setMouseGlobalCoords(x,y);
|
||||||
|
|
||||||
|
// Clear local coords - this was a click on root window so these are not needed
|
||||||
|
// By not including them, this allows the test skeleton generation tool to be smarter when generating code
|
||||||
|
// the code generator can be smarter because when local coords are present it can try the xui path with local coords
|
||||||
|
// and fallback to global coordinates only if needed.
|
||||||
|
// The drawback to this approach is sometimes a valid xui path will appear to work fine, but NOT interact with the UI element
|
||||||
|
// (VITA support not implemented yet or not visible to VITA due to widget further up xui path not being visible to VITA)
|
||||||
|
// For this reason it's best to provide hints where possible here by leaving out local coordinates
|
||||||
|
LLViewerEventRecorder::instance().setMouseLocalCoords(-1,-1);
|
||||||
|
LLViewerEventRecorder::instance().logMouseEvent(buttonstatestr,buttonname);
|
||||||
|
|
||||||
if (LLView::sDebugMouseHandling)
|
if (LLView::sDebugMouseHandling)
|
||||||
{
|
{
|
||||||
llinfos << buttonname << " Mouse " << buttonstatestr << " " << LLView::sMouseHandlerMessage << llendl;
|
llinfos << buttonname << " Mouse " << buttonstatestr << " " << LLViewerEventRecorder::instance().get_xui() << llendl;
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
} else if (LLView::sDebugMouseHandling)
|
||||||
else if (LLView::sDebugMouseHandling)
|
{
|
||||||
{
|
llinfos << buttonname << " Mouse " << buttonstatestr << " not handled by view" << llendl;
|
||||||
llinfos << buttonname << " Mouse " << buttonstatestr << " not handled by view" << llendl;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not allow tool manager to handle mouseclicks if we have disconnected
|
// Do not allow tool manager to handle mouseclicks if we have disconnected
|
||||||
if(!gDisconnected && LLToolMgr::getInstance()->getCurrentTool()->handleAnyMouseClick( x, y, mask, clicktype, down ) )
|
if(!gDisconnected && LLToolMgr::getInstance()->getCurrentTool()->handleAnyMouseClick( x, y, mask, clicktype, down ) )
|
||||||
{
|
{
|
||||||
|
LLViewerEventRecorder::instance().clear_xui();
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// If we got this far on a down-click, it wasn't handled.
|
// If we got this far on a down-click, it wasn't handled.
|
||||||
// Up-clicks, though, are always handled as far as the OS is concerned.
|
// Up-clicks, though, are always handled as far as the OS is concerned.
|
||||||
BOOL default_rtn = !down;
|
BOOL default_rtn = !down;
|
||||||
|
|
@ -1373,7 +1383,8 @@ BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask)
|
||||||
void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
|
void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
|
||||||
{
|
{
|
||||||
LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true);
|
LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true);
|
||||||
return gViewerKeyboard.scanKey(key, key_down, key_up, key_level);
|
gViewerKeyboard.scanKey(key, key_down, key_up, key_level);
|
||||||
|
return; // Be clear this function returns nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2519,6 +2530,8 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
|
||||||
||(gLoginMenuBarView && gLoginMenuBarView->handleKey(key, mask, TRUE))
|
||(gLoginMenuBarView && gLoginMenuBarView->handleKey(key, mask, TRUE))
|
||||||
||(gMenuHolder && gMenuHolder->handleKey(key, mask, TRUE)))
|
||(gMenuHolder && gMenuHolder->handleKey(key, mask, TRUE)))
|
||||||
{
|
{
|
||||||
|
lldebugs << "LLviewerWindow::handleKey handle nav keys for nav" << llendl;
|
||||||
|
LLViewerEventRecorder::instance().logKeyEvent(key,mask);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2533,12 +2546,14 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
|
||||||
&& keyboard_focus
|
&& keyboard_focus
|
||||||
&& keyboard_focus->handleKey(key,mask,FALSE))
|
&& keyboard_focus->handleKey(key,mask,FALSE))
|
||||||
{
|
{
|
||||||
|
LLViewerEventRecorder::instance().logKeyEvent(key,mask);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask))
|
if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask))
|
||||||
||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask)))
|
||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask)))
|
||||||
{
|
{
|
||||||
|
LLViewerEventRecorder::instance().logKeyEvent(key,mask);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2548,6 +2563,7 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
|
||||||
// if nothing has focus, go to first or last UI element as appropriate
|
// if nothing has focus, go to first or last UI element as appropriate
|
||||||
if (key == KEY_TAB && (mask & MASK_CONTROL || gFocusMgr.getKeyboardFocus() == NULL))
|
if (key == KEY_TAB && (mask & MASK_CONTROL || gFocusMgr.getKeyboardFocus() == NULL))
|
||||||
{
|
{
|
||||||
|
llwarns << "LLviewerWindow::handleKey give floaters first chance at tab key " << llendl;
|
||||||
if (gMenuHolder) gMenuHolder->hideMenus();
|
if (gMenuHolder) gMenuHolder->hideMenus();
|
||||||
|
|
||||||
// if CTRL-tabbing (and not just TAB with no focus), go into window cycle mode
|
// if CTRL-tabbing (and not just TAB with no focus), go into window cycle mode
|
||||||
|
|
@ -2562,11 +2578,13 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
|
||||||
{
|
{
|
||||||
mRootView->focusNextRoot();
|
mRootView->focusNextRoot();
|
||||||
}
|
}
|
||||||
|
LLViewerEventRecorder::instance().logKeyEvent(key,mask);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
// hidden edit menu for cut/copy/paste
|
// hidden edit menu for cut/copy/paste
|
||||||
if (gEditMenu && gEditMenu->handleAcceleratorKey(key, mask))
|
if (gEditMenu && gEditMenu->handleAcceleratorKey(key, mask))
|
||||||
{
|
{
|
||||||
|
LLViewerEventRecorder::instance().logKeyEvent(key,mask);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2606,18 +2624,27 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
|
||||||
|
|
||||||
if (keyboard_focus->handleKey(key, mask, FALSE))
|
if (keyboard_focus->handleKey(key, mask, FALSE))
|
||||||
{
|
{
|
||||||
|
|
||||||
|
lldebugs << "LLviewerWindow::handleKey - in 'traverse up' - no loops seen... just called keyboard_focus->handleKey an it returned true" << llendl;
|
||||||
|
LLViewerEventRecorder::instance().logKeyEvent(key,mask);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
} else {
|
||||||
|
lldebugs << "LLviewerWindow::handleKey - in 'traverse up' - no loops seen... just called keyboard_focus->handleKey an it returned FALSE" << llendl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( LLToolMgr::getInstance()->getCurrentTool()->handleKey(key, mask) )
|
if( LLToolMgr::getInstance()->getCurrentTool()->handleKey(key, mask) )
|
||||||
{
|
{
|
||||||
|
lldebugs << "LLviewerWindow::handleKey toolbar handling?" << llendl;
|
||||||
|
LLViewerEventRecorder::instance().logKeyEvent(key,mask);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try for a new-format gesture
|
// Try for a new-format gesture
|
||||||
if (LLGestureMgr::instance().triggerGesture(key, mask))
|
if (LLGestureMgr::instance().triggerGesture(key, mask))
|
||||||
{
|
{
|
||||||
|
lldebugs << "LLviewerWindow::handleKey new gesture feature" << llendl;
|
||||||
|
LLViewerEventRecorder::instance().logKeyEvent(key,mask);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2625,6 +2652,8 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
|
||||||
// don't pass it down to the menus.
|
// don't pass it down to the menus.
|
||||||
if (gGestureList.trigger(key, mask))
|
if (gGestureList.trigger(key, mask))
|
||||||
{
|
{
|
||||||
|
lldebugs << "LLviewerWindow::handleKey check gesture trigger" << llendl;
|
||||||
|
LLViewerEventRecorder::instance().logKeyEvent(key,mask);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2673,7 +2702,7 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
|
||||||
// HACK: Numeric keypad <enter> on Mac is Unicode 3
|
// HACK: Numeric keypad <enter> on Mac is Unicode 3
|
||||||
// HACK: Control-M on Windows is Unicode 13
|
// HACK: Control-M on Windows is Unicode 13
|
||||||
if ((uni_char == 13 && mask != MASK_CONTROL)
|
if ((uni_char == 13 && mask != MASK_CONTROL)
|
||||||
|| (uni_char == 3 && mask == MASK_NONE))
|
|| (uni_char == 3 && mask == MASK_NONE) )
|
||||||
{
|
{
|
||||||
if (mask != MASK_ALT)
|
if (mask != MASK_ALT)
|
||||||
{
|
{
|
||||||
|
|
@ -2696,14 +2725,7 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//// Topmost view gets a chance before the hierarchy
|
return TRUE;
|
||||||
//LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
|
|
||||||
//if (top_ctrl && top_ctrl->handleUnicodeChar( uni_char, FALSE ) )
|
|
||||||
//{
|
|
||||||
// return TRUE;
|
|
||||||
//}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
@ -2712,8 +2734,6 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
|
||||||
|
|
||||||
void LLViewerWindow::handleScrollWheel(S32 clicks)
|
void LLViewerWindow::handleScrollWheel(S32 clicks)
|
||||||
{
|
{
|
||||||
LLView::sMouseHandlerMessage.clear();
|
|
||||||
|
|
||||||
LLUI::resetMouseIdleTimer();
|
LLUI::resetMouseIdleTimer();
|
||||||
|
|
||||||
LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
|
LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
|
||||||
|
|
|
||||||
|
|
@ -5523,7 +5523,12 @@ void LLVOAvatar::addChild(LLViewerObject *childp)
|
||||||
{
|
{
|
||||||
if (!attachObject(childp))
|
if (!attachObject(childp))
|
||||||
{
|
{
|
||||||
mPendingAttachment.push_back(childp);
|
llwarns << "addChild() failed for "
|
||||||
|
<< childp->getID()
|
||||||
|
<< " item " << childp->getAttachmentItemID()
|
||||||
|
<< llendl;
|
||||||
|
// MAINT-3312 backout
|
||||||
|
// mPendingAttachment.push_back(childp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -5557,21 +5562,26 @@ LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* vi
|
||||||
|
|
||||||
if (!attachment)
|
if (!attachment)
|
||||||
{
|
{
|
||||||
llwarns << "Object attachment point invalid: " << attachmentID << llendl;
|
llwarns << "Object attachment point invalid: " << attachmentID
|
||||||
|
<< " trying to use 1 (chest)"
|
||||||
|
<< llendl;
|
||||||
|
|
||||||
for (int i = 0; i < 15 && !attachment; i++)
|
attachment = get_if_there(mAttachmentPoints, 1, (LLViewerJointAttachment*)NULL); // Arbitrary using 1 (chest)
|
||||||
|
if (attachment)
|
||||||
{
|
{
|
||||||
attachment = get_if_there(mAttachmentPoints, i, (LLViewerJointAttachment*)NULL); // Arbitrary using 1 (chest)
|
llwarns << "Object attachment point invalid: " << attachmentID
|
||||||
|
<< " on object " << viewer_object->getID()
|
||||||
if (attachment)
|
<< " attachment item " << viewer_object->getAttachmentItemID()
|
||||||
{
|
<< " falling back to 1 (chest)"
|
||||||
llwarns << "Object attachment point falling back to : " << i << llendl;
|
<< llendl;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (!attachment)
|
|
||||||
{
|
{
|
||||||
llerrs << "Could not find any object attachment point for: " << attachmentID << llendl;
|
llwarns << "Object attachment point invalid: " << attachmentID
|
||||||
|
<< " on object " << viewer_object->getID()
|
||||||
|
<< " attachment item " << viewer_object->getAttachmentItemID()
|
||||||
|
<< "Unable to use fallback attachment point 1 (chest)"
|
||||||
|
<< llendl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5643,16 +5653,22 @@ void LLVOAvatar::lazyAttach()
|
||||||
|
|
||||||
for (U32 i = 0; i < mPendingAttachment.size(); i++)
|
for (U32 i = 0; i < mPendingAttachment.size(); i++)
|
||||||
{
|
{
|
||||||
if (mPendingAttachment[i]->mDrawable)
|
LLPointer<LLViewerObject> cur_attachment = mPendingAttachment[i];
|
||||||
|
if (cur_attachment->mDrawable)
|
||||||
{
|
{
|
||||||
if (!attachObject(mPendingAttachment[i]))
|
if (!attachObject(cur_attachment))
|
||||||
{
|
{ // Drop it
|
||||||
still_pending.push_back(mPendingAttachment[i]);
|
llwarns << "attachObject() failed for "
|
||||||
|
<< cur_attachment->getID()
|
||||||
|
<< " item " << cur_attachment->getAttachmentItemID()
|
||||||
|
<< llendl;
|
||||||
|
// MAINT-3312 backout
|
||||||
|
//still_pending.push_back(cur_attachment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
still_pending.push_back(mPendingAttachment[i]);
|
still_pending.push_back(cur_attachment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5959,6 +5975,28 @@ BOOL LLVOAvatar::isWearingWearableType(LLWearableType::EType type) const
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LLViewerObject * LLVOAvatar::findAttachmentByID( const LLUUID & target_id ) const
|
||||||
|
{
|
||||||
|
for(attachment_map_t::const_iterator attachment_points_iter = mAttachmentPoints.begin();
|
||||||
|
attachment_points_iter != gAgentAvatarp->mAttachmentPoints.end();
|
||||||
|
++attachment_points_iter)
|
||||||
|
{
|
||||||
|
LLViewerJointAttachment* attachment = attachment_points_iter->second;
|
||||||
|
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
|
||||||
|
attachment_iter != attachment->mAttachedObjects.end();
|
||||||
|
++attachment_iter)
|
||||||
|
{
|
||||||
|
LLViewerObject *attached_object = (*attachment_iter);
|
||||||
|
if (attached_object &&
|
||||||
|
attached_object->getID() == target_id)
|
||||||
|
{
|
||||||
|
return attached_object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
|
|
|
||||||
|
|
@ -731,6 +731,8 @@ public:
|
||||||
void cleanupAttachedMesh( LLViewerObject* pVO );
|
void cleanupAttachedMesh( LLViewerObject* pVO );
|
||||||
static LLVOAvatar* findAvatarFromAttachment(LLViewerObject* obj);
|
static LLVOAvatar* findAvatarFromAttachment(LLViewerObject* obj);
|
||||||
/*virtual*/ BOOL isWearingWearableType(LLWearableType::EType type ) const;
|
/*virtual*/ BOOL isWearingWearableType(LLWearableType::EType type ) const;
|
||||||
|
LLViewerObject * findAttachmentByID( const LLUUID & target_id ) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object);
|
LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object);
|
||||||
void lazyAttach();
|
void lazyAttach();
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue