Pull merge from lindenlab/viewer-release

master
Merov Linden 2013-11-18 16:07:55 -08:00
commit ce5baf14ac
194 changed files with 9143 additions and 1763 deletions

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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} )

View 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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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,

View File

@ -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.

View File

@ -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, "");

View File

@ -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);

View File

@ -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++;
}
}
}

View File

@ -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(); };

View File

@ -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;

View File

@ -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

View File

@ -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());

View File

@ -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);

View File

@ -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;
} }
} }

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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));
} }

View File

@ -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;
}; };

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
} }

View File

@ -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)

View File

@ -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);
}

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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"

View File

@ -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>

View File

@ -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"/>

View File

@ -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(),

View File

@ -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

View File

@ -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);
} }
} }
} }

View File

@ -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;

View File

@ -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:

View File

@ -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 );

View File

@ -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

View File

@ -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)
{ {

View File

@ -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.
*/ */

View File

@ -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;
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////

View File

@ -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))

View File

@ -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"));

View File

@ -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);
} }

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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")
{ {

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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();
}

View File

@ -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

View File

@ -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 );

View File

@ -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

View File

@ -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)
{ {

View File

@ -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"));
} }
} }

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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;
}; };

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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())
{ {

View File

@ -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);
}

View File

@ -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

View File

@ -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()

View File

@ -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);

View File

@ -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
{ {

View File

@ -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

View File

@ -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");

View File

@ -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];
} }

View File

@ -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)
{ {

View File

@ -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");

View File

@ -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,

View File

@ -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;

View File

@ -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()

View File

@ -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();
}
}

View File

@ -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"))
{ {

View File

@ -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();

View File

@ -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

View File

@ -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