Merge latest viewer-release with FBC

simon 2013-10-23 14:14:36 -07:00
commit 64c5afa196
135 changed files with 8830 additions and 1567 deletions

View File

@ -467,3 +467,4 @@ fe4f7c5e9fd27e09d03deb1cc9ab3e5093f6309e 3.6.3-release
bf6d453046011a11de2643fac610cc5258650f82 3.6.5-release
ae457ece77001767ae9613148c495e7b98cc0f4a 3.6.7-release
d40c66e410741de7e90b1ed6dac28dd8a2d7e1f6 3.6.8-release
70eda3721d36df3e00730629c42a1304e5bc65b8 3.6.9-release

View File

@ -27,9 +27,6 @@ Linux.distcc_version =
Linux.gcc_version = /usr/bin/gcc-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 ####
#
@ -50,6 +47,18 @@ sourceid = ""
################################################################
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...
viewer-development.show_changes_since = last_sprint

View File

@ -1965,11 +1965,11 @@
<key>package_description</key>
<map>
<key>description</key>
<string>Spell checking dictionaries</string>
<string>Second Life Viewer</string>
<key>license</key>
<string>various open</string>
<string>LGPL</string>
<key>name</key>
<string>dictionaries</string>
<string>Second Life Viewer</string>
<key>platforms</key>
<map>
<key>common</key>

View File

@ -38,22 +38,22 @@ build_dir_CYGWIN()
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()
{
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()
{
v=${last_built_variant:-Release}
d=$(build_dir_CYGWIN $v)
if [ -r "$d/newview/$v/touched.bat" ]
if [ -r "$d/newview/$additional_package_name$v/touched.bat" ]
then
p=$(sed 's:.*=::' "$d/newview/$v/touched.bat")
echo "$d/newview/$v/$p"
p=$(sed 's:.*=::' "$d/newview/$additional_package_name$v/touched.bat")
echo "$d/newview/$additional_package_name$v/$p"
fi
}
@ -355,10 +355,28 @@ then
# Coverity doesn't package, so it's ok, anything else is fail
succeeded=$build_coverity
else
# Upload base package.
upload_item installer "$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
# 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
Release)
# Upload crash reporter files

View File

@ -175,8 +175,11 @@ Ansariel Hiller
STORM-1685
STORM-1713
STORM-1899
STORM-1932
STORM-1933
MAINT-2368
STORM-1931
MAINT-2773
Aralara Rajal
Arare Chantilly
CHUIBUG-191
@ -304,9 +307,13 @@ Christopher Organiser
Ciaran Laval
Cinder Roxley
BUG-2326
OPEN-185
STORM-1703
STORM-1948
STORM-1888
STORM-1958
STORM-1952
STORM-1951
Clara Young
Coaldust Numbers
VWR-1095
@ -652,7 +659,7 @@ Jonathan Yap
STORM-1809
STORM-1793
STORM-1810
STORM-1877
STORM-1838
STORM-1892
STORM-1894
STORM-1860
@ -662,8 +669,11 @@ Jonathan Yap
STORM-1858
STORM-1862
STORM-1918
STORM-1929
STORM-1953
OPEN-161
STORM-1953
STORM-1957
Kadah Coba
STORM-1060
STORM-1843
@ -679,7 +689,9 @@ Kagehi Kohn
Kaimen Takahe
Katharine Berry
STORM-1900
OPEN-149
STORM-1940
OPEN-149
STORM-1941
Keklily Longfall
Ken Lavender
@ -928,7 +940,9 @@ Nicky Dasmijn
STORM-1936
BUG-3605
CHUIBUG-197
OPEN-187
STORM-1937
OPEN-187
Nicky Perian
OPEN-1
STORM-1087
@ -1125,6 +1139,7 @@ Slee Mayo
snowy Sidran
Sovereign Engineer
MAINT-2334
OPEN-189
SpacedOut Frye
VWR-34
VWR-45
@ -1293,6 +1308,7 @@ Westley Streeter
Whimsy Winx
Whirly Fizzle
STORM-1895
VWR-29543
MAINT-873
STORM-1930
Whoops Babii
@ -1356,6 +1372,7 @@ YongYong Francois
Zak Westminster
Zai Lynch
VWR-19505
STORM-1902
Zana Kohime
Zaren Alexander
Zarkonnen Decosta

View File

@ -63,10 +63,11 @@ add_subdirectory(${VIEWER_PREFIX}test)
# viewer media plugins
add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins)
# llplugin testbed code (is this the right way to include it?)
if (LL_TESTS AND NOT LINUX)
add_subdirectory(${VIEWER_PREFIX}test_apps/llplugintest)
endif (LL_TESTS AND NOT LINUX)
# llplugin testbed code (is this the right way to include it?)
if (LL_TESTS AND NOT LINUX)
add_subdirectory(${VIEWER_PREFIX}test_apps/llplugintest)
add_subdirectory(${VIEWER_PREFIX}test_apps/llfbconnecttest)
endif (LL_TESTS AND NOT LINUX)
if (LINUX)
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})
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(
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_STRIP_TRAILING_WHITESPACE
)
if ("${VIEWER_VERSION_REVISION}" MATCHES "^[0-9]+$")
message("Revision (from hg) ${VIEWER_VERSION_REVISION}")
else ("${VIEWER_VERSION_REVISION}" MATCHES "^[0-9]+$")
message("Revision not set (repository not found?); using 0")
set(VIEWER_VERSION_REVISION 0 )
message("Revision not set, repository not found, using ${VIEWER_VERSION_REVISION}")
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)
message("Revision not set, 'hg' not found (${MERCURIAL}), using ${VIEWER_VERSION_REVISION}")
endif (DEFINED MERCURIAL)
endif (DEFINED MERCURIAL AND DEFINED WORDCOUNT AND DEFINED SED)
endif (DEFINED ENV{revision})
message("Building '${VIEWER_CHANNEL}' Version ${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}")
else ( EXISTS ${VIEWER_VERSION_BASE_FILE} )

View File

@ -224,15 +224,98 @@ def main():
for opt in args:
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.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
# and used in a .bat file - yeah, it sucks, but this is the simplest...
touch = args.get('touch')
if touch:
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()
print 'touched', touch
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, F32 a); // Initializes LLColor4 to (r. g, b, a)
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)
explicit LLColor4(const LLSD& sd);
explicit LLColor4(const LLColor4U& color4u); // "explicit" to avoid automatic conversion

View File

@ -217,7 +217,8 @@ static void request(
Injector* body_injector,
LLCurl::ResponderPtr responder,
const F32 timeout = HTTP_REQUEST_EXPIRY_SECS,
const LLSD& headers = LLSD()
const LLSD& headers = LLSD(),
bool follow_redirects = true
)
{
if (!LLHTTPClient::hasPump())
@ -231,7 +232,7 @@ static void request(
}
LLPumpIO::chain_t chain;
LLURLRequest* req = new LLURLRequest(method, url);
LLURLRequest* req = new LLURLRequest(method, url, follow_redirects);
if(!req->isValid())//failed
{
if (responder)
@ -334,7 +335,8 @@ void LLHTTPClient::getByteRange(
S32 bytes,
ResponderPtr responder,
const LLSD& hdrs,
const F32 timeout)
const F32 timeout,
bool follow_redirects /* = true */)
{
LLSD headers = hdrs;
if(offset > 0 || bytes > 0)
@ -342,37 +344,42 @@ void LLHTTPClient::getByteRange(
std::string range = llformat("bytes=%d-%d", offset, offset+bytes-1);
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(
const std::string& url,
ResponderPtr responder,
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;
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.

View File

@ -63,10 +63,15 @@ public:
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, const LLSD& headers=LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
static void get(const std::string& url, ResponderPtr, const LLSD& headers = LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
static void get(const std::string& url, const LLSD& query, ResponderPtr, const LLSD& headers = LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS,
bool follow_redirects = true);
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, 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(
const std::string& url,
@ -74,8 +79,10 @@ public:
ResponderPtr,
const LLSD& headers = LLSD(),
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);
static void getHeaderOnly(const std::string& url, ResponderPtr, 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(
const std::string& url,

View File

@ -126,7 +126,7 @@ enum EInstantMessage
IM_LURE_ACCEPTED = 23,
IM_LURE_DECLINED = 24,
IM_GODLIKE_LURE_USER = 25,
IM_YET_TO_BE_USED = 26,
IM_TELEPORT_REQUEST = 26,
// IM that notifie of a new group election.
// Name is name of person who called vote.

View File

@ -150,16 +150,19 @@ std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action)
return VERBS[action];
}
LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action) :
mAction(action)
LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, bool follow_redirects /* = true */) :
mAction(action),
mFollowRedirects(follow_redirects)
{
initialize();
}
LLURLRequest::LLURLRequest(
LLURLRequest::ERequestAction action,
const std::string& url) :
mAction(action)
const std::string& url,
bool follow_redirects /* = true */) :
mAction(action),
mFollowRedirects(follow_redirects)
{
initialize();
setURL(url);
@ -479,12 +482,18 @@ bool LLURLRequest::configure()
case HTTP_HEAD:
mDetail->mCurlRequest->setopt(CURLOPT_HEADER, 1);
mDetail->mCurlRequest->setopt(CURLOPT_NOBODY, 1);
mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1);
if (mFollowRedirects)
{
mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1);
}
rv = true;
break;
case HTTP_GET:
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
mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, "");

View File

@ -95,7 +95,7 @@ public:
*
* @param action One of the ERequestAction enumerations.
*/
LLURLRequest(ERequestAction action);
LLURLRequest(ERequestAction action, bool follow_redirects = true);
/**
* @brief Constructor.
@ -103,7 +103,7 @@ public:
* @param action One of the ERequestAction enumerations.
* @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.
@ -219,10 +219,11 @@ protected:
};
EState mState;
ERequestAction mAction;
bool mFollowRedirects;
LLURLRequestDetail* mDetail;
LLIOPipe::ptr_t mCompletionCallback;
S32 mRequestTransferedBytes;
S32 mResponseTransferedBytes;
S32 mRequestTransferedBytes;
S32 mResponseTransferedBytes;
static CURLcode _sslCtxCallback(CURL * curl, void *sslctx, void *param);

View File

@ -87,6 +87,16 @@ std::string LLPluginCookieStore::Cookie::getKey() const
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 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
static std::string quoteString(const std::string &s);
static std::string unquoteString(const std::string &s);
void removeCookiesByDomain(const std::string &domain);
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.
std::string getKey() const;
std::string getDomain() const;
const std::string &getCookie() const { return mCookie; };
bool isSessionCookie() const { return mDate.isNull(); };

View File

@ -75,6 +75,7 @@ set(llui_SOURCE_FILES
llmultislider.cpp
llmultisliderctrl.cpp
llnotifications.cpp
llnotificationslistener.cpp
llnotificationsutil.cpp
llpanel.cpp
llprogressbar.cpp
@ -128,6 +129,7 @@ set(llui_SOURCE_FILES
llviewmodel.cpp
llview.cpp
llviewquery.cpp
llviewereventrecorder.cpp
llwindowshade.cpp
llxuiparser.cpp
)
@ -183,6 +185,7 @@ set(llui_HEADER_FILES
llmultislider.h
llnotificationptr.h
llnotifications.h
llnotificationslistener.h
llnotificationsutil.h
llnotificationtemplate.h
llnotificationvisibilityrule.h
@ -240,6 +243,7 @@ set(llui_HEADER_FILES
llviewinject.h
llviewmodel.h
llview.h
llviewereventrecorder.h
llviewquery.h
llwindowshade.h
llxuiparser.h

View File

@ -49,6 +49,7 @@
#include "lluictrlfactory.h"
#include "llhelp.h"
#include "lldockablefloater.h"
#include "llviewereventrecorder.h"
static LLDefaultChildRegistry::Register<LLButton> r("button");
@ -443,6 +444,8 @@ BOOL LLButton::handleMouseDown(S32 x, S32 y, MASK mask)
*/
LLUICtrl::handleMouseDown(x, y, mask);
LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname());
if(mMouseDownSignal) (*mMouseDownSignal)(this, LLSD());
mMouseDownTimer.start();
@ -473,6 +476,7 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
* by calling LLUICtrl::mMouseUpSignal(x, y, mask);
*/
LLUICtrl::handleMouseUp(x, y, mask);
LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname());
// Regardless of where mouseup occurs, handle callback
if(mMouseUpSignal) (*mMouseUpSignal)(this, LLSD());

View File

@ -62,8 +62,8 @@ public:
virtual void draw();
virtual void onCommit();
/*virtual*/ void onFocusReceived();
/*virtual*/ void onFocusLost();
/*virtual*/ void onFocusReceived();
/*virtual*/ void onFocusLost();
void enableSingleLineMode(bool single_line_mode);
boost::signals2::connection setTextExpandedCallback(const commit_signal_t::slot_type& cb);

View File

@ -29,7 +29,7 @@
// mini-map floater, etc.
#include "linden_common.h"
#include "llviewereventrecorder.h"
#include "llfloater.h"
#include "llfocusmgr.h"
@ -509,8 +509,8 @@ LLFloater::~LLFloater()
if( gFocusMgr.childHasKeyboardFocus(this))
{
// Just in case we might still have focus here, release it.
releaseFocus();
// Just in case we might still have focus here, release it.
releaseFocus();
}
// 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)
{
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
if (getSoundFlags() != SILENT
@ -696,6 +699,7 @@ void LLFloater::openFloater(const LLSD& key)
void LLFloater::closeFloater(bool app_quitting)
{
llinfos << "Closing floater " << getName() << llendl;
LLViewerEventRecorder::instance().logVisibilityChange( getPathname(), getName(), false,"floater"); // Last param is event subtype or empty string
if (app_quitting)
{
LLFloater::sQuitting = true;
@ -1335,7 +1339,7 @@ void LLFloater::setFocus( BOOL b )
{
return;
}
LLUICtrl* last_focus = gFocusMgr.getLastFocusForGroup(this);
LLView* last_focus = gFocusMgr.getLastFocusForGroup(this);
// a descendent already has focus
BOOL child_had_focus = hasFocus();
@ -1542,6 +1546,17 @@ BOOL LLFloater::handleScrollWheel(S32 x, S32 y, S32 clicks)
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
BOOL LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)
{
@ -1562,7 +1577,11 @@ BOOL LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)
else
{
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; }
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 handleDoubleClick(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;
}
LLUICtrl* LLFocusMgr::getLastFocusForGroup(LLView* subtree_root) const
LLView* LLFocusMgr::getLastFocusForGroup(LLView* subtree_root) const
{
if (subtree_root)
{
@ -477,7 +477,7 @@ LLUICtrl* LLFocusMgr::getLastFocusForGroup(LLView* subtree_root) const
if (found_it != mImpl->mFocusHistory.end())
{
// found last focus for this subtree
return static_cast<LLUICtrl*>(found_it->second.get());
return found_it->second.get();
}
}
return NULL;

View File

@ -97,7 +97,7 @@ public:
void triggerFocusFlash();
BOOL getAppHasFocus() const { return mAppHasFocus; }
void setAppHasFocus(BOOL focus);
LLUICtrl* getLastFocusForGroup(LLView* subtree_root) const;
LLView* getLastFocusForGroup(LLView* subtree_root) const;
void clearLastFocusForGroup(LLView* subtree_root);
// If setKeyboardFocus(NULL) is called, and there is a non-NULL default

View File

@ -185,7 +185,7 @@ LLFolderView::LLFolderView(const Params& p)
mAutoOpenCandidate = NULL;
mAutoOpenTimer.stop();
mKeyboardSelection = FALSE;
mIndentation = p.folder_indentation;
mIndentation = getParentFolder() ? getParentFolder()->getIndentation() + mLocalIndentation : 0;
//clear label
// go ahead and render root folder as usual
@ -1613,7 +1613,7 @@ void LLFolderView::update()
{
getFolderViewModel()->getFilter().clearModified();
}
// automatically show matching items, and select first one if we had a selection
if (mNeedsAutoSelect)
{
@ -1653,13 +1653,13 @@ void LLFolderView::update()
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)
// It also handles the open/close folder animation
if (is_visible)
if ( is_visible )
{
sanitizeSelection();
if (needsArrange())
if( needsArrange() )
{
S32 height = 0;
S32 width = 0;

View File

@ -307,7 +307,12 @@ std::set<LLFolderViewItem*> LLFolderViewItem::getSelectionList() const
// addToFolder() returns TRUE if it succeeds. FALSE otherwise
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)
{
folder->addFolder(this);
// Compute indentation since parent folder changed
mIndentation = (getParentFolder())
? getParentFolder()->getIndentation() + mLocalIndentation
: 0;
}
static LLFastTimer::DeclareTimer FTM_ARRANGE("Arrange");
@ -1109,7 +1119,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height )
BOOL LLFolderViewFolder::needsArrange()
{
return mLastArrangeGeneration < getRoot()->getArrangeGeneration();
return mLastArrangeGeneration < getRoot()->getArrangeGeneration();
}
// Passes selection information on to children and record selection

View File

@ -1206,6 +1206,7 @@ LLNotifications::LLNotifications()
: LLNotificationChannelBase(LLNotificationFilters::includeEverything),
mIgnoreAllNotifications(false)
{
mListener.reset(new LLNotificationsListener(*this));
LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2));
}

View File

@ -98,6 +98,8 @@
#include "llrefcount.h"
#include "llsdparam.h"
#include "llnotificationslistener.h"
class LLAvatarName;
typedef enum e_notification_priority
{
@ -978,6 +980,8 @@ private:
bool mIgnoreAllNotifications;
boost::scoped_ptr<LLNotificationsListener> mListener;
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 "lltabcontainer.h"
#include "llviewereventrecorder.h"
#include "llfocusmgr.h"
#include "lllocalcliprect.h"
#include "llrect.h"
@ -583,6 +583,11 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask )
tab_button->setFocus(TRUE);
}
}
if (handled) {
// Note: May need to also capture local coords right here ?
LLViewerEventRecorder::instance().update_xui(getPathname( ));
}
return handled;
}
@ -634,30 +639,33 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask )
BOOL handled = FALSE;
BOOL has_scroll_arrows = (getMaxScrollPos() > 0) && !getTabsHidden();
S32 local_x = x - getRect().mLeft;
S32 local_y = y - getRect().mBottom;
if (has_scroll_arrows)
{
if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y))
{
S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
handled = mJumpPrevArrowBtn->handleMouseUp(local_x, local_y, mask);
}
else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y))
{
S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft;
S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom;
local_x = x - mJumpNextArrowBtn->getRect().mLeft;
local_y = y - mJumpNextArrowBtn->getRect().mBottom;
handled = mJumpNextArrowBtn->handleMouseUp(local_x, local_y, mask);
}
else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y))
{
S32 local_x = x - mPrevArrowBtn->getRect().mLeft;
S32 local_y = y - mPrevArrowBtn->getRect().mBottom;
local_x = x - mPrevArrowBtn->getRect().mLeft;
local_y = y - mPrevArrowBtn->getRect().mBottom;
handled = mPrevArrowBtn->handleMouseUp(local_x, local_y, mask);
}
else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y))
{
S32 local_x = x - mNextArrowBtn->getRect().mLeft;
S32 local_y = y - mNextArrowBtn->getRect().mBottom;
local_x = x - mNextArrowBtn->getRect().mLeft;
local_y = y - mNextArrowBtn->getRect().mBottom;
handled = mNextArrowBtn->handleMouseUp(local_x, local_y, mask);
}
}
@ -681,6 +689,10 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask )
}
gFocusMgr.setMouseCapture(NULL);
}
if (handled) {
// Note: may need to capture local coords here
LLViewerEventRecorder::instance().update_xui(getPathname( ));
}
return handled;
}
@ -1076,21 +1088,21 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
if (mIsVertical)
{
p.name(std::string("vert tab button"));
p.image_unselected(mMiddleTabParams.tab_left_image_unselected);
p.image_selected(mMiddleTabParams.tab_left_image_selected);
p.follows.flags = p.follows.flags() | FOLLOWS_TOP;
p.name("vtab_"+std::string(child->getName()));
p.image_unselected(mMiddleTabParams.tab_left_image_unselected);
p.image_selected(mMiddleTabParams.tab_left_image_selected);
p.follows.flags = p.follows.flags() | FOLLOWS_TOP;
}
else
{
p.name(std::string(child->getName()) + " tab");
p.visible(false);
p.image_unselected(tab_img);
p.image_selected(tab_selected_img);
p.follows.flags = p.follows.flags() | (getTabPosition() == TOP ? FOLLOWS_TOP : FOLLOWS_BOTTOM);
// Try to squeeze in a bit more text
p.pad_left( mLabelPadLeft );
p.pad_right(2);
{
p.name("htab_"+std::string(child->getName()));
p.visible(false);
p.image_unselected(tab_img);
p.image_selected(tab_selected_img);
p.follows.flags = p.follows.flags() | (getTabPosition() == TOP ? FOLLOWS_TOP : FOLLOWS_BOTTOM);
// Try to squeeze in a bit more text
p.pad_left( mLabelPadLeft );
p.pad_right(2);
}
// *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
#include "lluictrl.h"
#include "llviewereventrecorder.h"
#include "llfocusmgr.h"
#include "llpanel.h"
#include "lluictrlfactory.h"
@ -308,22 +308,40 @@ void LLUICtrl::onMouseLeave(S32 x, S32 y, MASK mask)
//virtual
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);
if (mMouseDownSignal)
{
(*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;
}
//virtual
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);
if (handled) {
LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-56,-56,getPathname());
}
if (mMouseUpSignal)
{
(*mMouseUpSignal)(this,x,y,mask);
}
lldebugs << "LLUICtrl::handleMouseUp - handled for xui " << getPathname() << " - is returning as: " << handled << " " << llendl;
return handled;
}

View File

@ -48,7 +48,9 @@
#include "lluictrlfactory.h"
#include "lltooltip.h"
#include "llsdutil.h"
#include "llsdserialize.h"
#include "llviewereventrecorder.h"
#include "llkeyboard.h"
// for ui edit hack
#include "llbutton.h"
#include "lllineeditor.h"
@ -642,13 +644,27 @@ void LLView::setVisible(BOOL visible)
// virtual
void LLView::handleVisibilityChange ( BOOL new_visibility )
{
BOOL old_visibility;
BOOST_FOREACH(LLView* viewp, mChildList)
{
// 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 );
}
// 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();
}
// This is NOT event recording related
void LLView::logMouseEvent()
{
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 )
|| (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();
return viewp;
}
}
@ -766,6 +790,7 @@ LLView* LLView::childrenHandleToolTip(S32 x, S32 y, MASK mask)
if (viewp->handleToolTip(local_x, local_y, mask)
|| viewp->blockMouseEvent(local_x, local_y))
{
// This is NOT event recording related
viewp->logMouseEvent();
return viewp;
}
@ -824,6 +849,7 @@ LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask)
if (viewp->handleHover(local_x, local_y, mask)
|| viewp->blockMouseEvent(local_x, local_y))
{
// This is NOT event recording related
viewp->logMouseEvent();
return viewp;
}
@ -907,10 +933,12 @@ BOOL LLView::handleKey(KEY key, MASK mask, BOOL called_from_parent)
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 );
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);
}
if (handled)
{
LLViewerEventRecorder::instance().logKeyUnicodeEvent(uni_char);
}
return handled;
}
@ -987,12 +1020,16 @@ BOOL LLView::hasMouseCapture()
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)
{
return childrenHandleMouseDown( x, y, mask ) != NULL;
LLView* r= childrenHandleMouseDown(x, y, mask );
return (r!=NULL);
}
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)
{
return childrenHandleMouseEvent(&LLView::handleMouseUp, x, y, mask);
return childrenHandleMouseEvent(&LLView::handleMouseUp, x, y, 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

@ -25,6 +25,9 @@
* $/LicenseInfo$
*/
#ifndef LL_LLWINDOWMACOSX_OBJC_H
#define LL_LLWINDOWMACOSX_OBJC_H
#include <map>
#include <vector>
@ -144,3 +147,5 @@ NSWindowRef getMainAppWindow();
GLViewRef getGLView();
unsigned int getModifiers();
#endif // LL_LLWINDOWMACOSX_OBJC_H

View File

@ -1300,6 +1300,8 @@ void LLWindowMacOSX::setupFailure(const std::string& text, const std::string& ca
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)
{
switch (id)

View File

@ -391,7 +391,7 @@ LLControlVariable* LLControlGroup::declareControl(const std::string& name, eCont
}
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;
}
@ -630,14 +630,14 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require
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;
}
LLXmlTreeNode* rootp = xml_controls.getRoot();
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;
}
@ -650,7 +650,7 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require
// Check file 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;
}
@ -668,7 +668,7 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require
if (!name.empty())
{
//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();
continue;
@ -822,7 +822,7 @@ U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only
LLControlVariable* control = iter->second;
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) )
{
@ -838,12 +838,12 @@ U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only
{
LLSDSerialize::toPrettyXML(settings, file);
file.close();
llinfos << "Saved to " << filename << llendl;
LL_INFOS("Settings") << "Saved to " << filename << LL_ENDL;
}
else
{
// 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 num_saved;
@ -856,14 +856,14 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v
infile.open(filename);
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;
}
if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(settings, infile))
{
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);
}
@ -976,6 +976,7 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v
++validitems;
}
LL_DEBUGS("Settings") << "Loaded " << validitems << " settings from " << filename << LL_ENDL;
return validitems;
}
@ -1012,7 +1013,7 @@ void main()
BOOL_CONTROL baz;
U32 count = gGlobals.loadFromFile("controls.ini");
llinfos << "Loaded " << count << " controls" << llendl;
LL_INFOS("Settings") << "Loaded " << count << " controls" << LL_ENDL;
// test insertion
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);
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)
{
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)
{
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)
{
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);

View File

@ -191,6 +191,7 @@ set(viewer_SOURCE_FILES
llexpandabletextbox.cpp
llexternaleditor.cpp
llface.cpp
llfacebookconnect.cpp
llfasttimerview.cpp
llfavoritesbar.cpp
llfeaturemanager.cpp
@ -273,6 +274,7 @@ set(viewer_SOURCE_FILES
llfloatersettingsdebug.cpp
llfloatersidepanelcontainer.cpp
llfloatersnapshot.cpp
llfloatersocial.cpp
llfloatersounddevices.cpp
llfloaterspellchecksettings.cpp
llfloatertelehub.cpp
@ -508,6 +510,7 @@ set(viewer_SOURCE_FILES
llsidetraypanelcontainer.cpp
llsky.cpp
llslurl.cpp
llsnapshotlivepreview.cpp
llspatialpartition.cpp
llspeakers.cpp
llspeakingindicatormanager.cpp
@ -776,6 +779,7 @@ set(viewer_HEADER_FILES
llexpandabletextbox.h
llexternaleditor.h
llface.h
llfacebookconnect.h
llfasttimerview.h
llfavoritesbar.h
llfeaturemanager.h
@ -858,6 +862,7 @@ set(viewer_HEADER_FILES
llfloatersettingsdebug.h
llfloatersidepanelcontainer.h
llfloatersnapshot.h
llfloatersocial.h
llfloatersounddevices.h
llfloaterspellchecksettings.h
llfloatertelehub.h
@ -1082,6 +1087,7 @@ set(viewer_HEADER_FILES
llsidetraypanelcontainer.h
llsky.h
llslurl.h
llsnapshotlivepreview.h
llspatialpartition.h
llspeakers.h
llspeakingindicatormanager.h

View File

@ -1 +1 @@
3.6.9
3.6.10

View File

@ -260,6 +260,16 @@
is_running_function="Floater.IsOpen"
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"
available_in_toybox="true"
icon="Command_Speak_Icon"

View File

@ -4941,6 +4941,16 @@
<key>Value</key>
<array />
</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>
<map>
<key>Comment</key>
@ -10455,6 +10465,17 @@
<key>Value</key>
<integer>0</integer>
</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>
<map>
<key>Comment</key>
@ -13095,6 +13116,17 @@
<key>Value</key>
<integer>0</integer>
</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>
<map>
<key>Comment</key>

View File

@ -6,6 +6,7 @@
<command name="speak"/>
<command name="destinations"/>
<command name="people"/>
<command name="social"/>
<command name="profile"/>
<command name="move"/>
<command name="view"/>

View File

@ -112,6 +112,11 @@ BOOL LLAgentUI::buildLocationString(std::string& str, ELocationFormat fmt,const
case LOCATION_FORMAT_NORMAL:
buffer = llformat("%s", region_name.c_str());
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:
buffer = llformat("%s%s%s",
region_name.c_str(),
@ -143,6 +148,11 @@ BOOL LLAgentUI::buildLocationString(std::string& str, ELocationFormat fmt,const
case LOCATION_FORMAT_NORMAL:
buffer = llformat("%s, %s", parcel_name.c_str(), region_name.c_str());
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:
buffer = llformat("%s, %s (%d, %d, %d)",
parcel_name.c_str(),

View File

@ -35,6 +35,7 @@ public:
enum ELocationFormat
{
LOCATION_FORMAT_NORMAL, // Parcel
LOCATION_FORMAT_NORMAL_COORDS, // Parcel (x, y, z)
LOCATION_FORMAT_LANDMARK, // Parcel, Region
LOCATION_FORMAT_NO_MATURITY, // Parcel, Region (x, y, z)
LOCATION_FORMAT_NO_COORDS, // Parcel, Region - Maturity

View File

@ -223,6 +223,10 @@
#include "llmachineid.h"
#include "llmainlooprepeater.h"
#include "llviewereventrecorder.h"
// *FIX: These extern globals should be cleaned up.
// The globals either represent state/config/resource-storage of either
// this app, or another 'component' of the viewer. App globals should be
@ -696,6 +700,7 @@ LLAppViewer::LLAppViewer() :
LLAppViewer::~LLAppViewer()
{
delete mSettingsLocationList;
LLViewerEventRecorder::instance().~LLViewerEventRecorder();
LLLoginInstance::instance().setUpdaterService(0);
@ -2250,13 +2255,13 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key,
BOOST_FOREACH(const SettingsFile& file, group.files)
{
llinfos << "Attempting to load settings for the group " << file.name()
<< " - from location " << location_key << llendl;
LL_INFOS("Settings") << "Attempting to load settings for the group " << file.name()
<< " - from location " << location_key << LL_ENDL;
LLControlGroup* settings_group = LLControlGroup::getInstance(file.name);
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;
}
@ -2285,7 +2290,7 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key,
if(settings_group->loadFromFile(full_settings_path, set_defaults, file.persistent))
{ // success!
llinfos << "Loaded settings file " << full_settings_path << llendl;
LL_INFOS("Settings") << "Loaded settings file " << full_settings_path << LL_ENDL;
}
else
{ // 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
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",
gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Global")));
gSavedSettings.setString("VersionChannelName", LLVersionInfo::getChannel());
#ifndef LL_RELEASE_FOR_DOWNLOAD
// provide developer build only overrides for these control variables that are not
// persisted to settings.xml
@ -2460,8 +2463,8 @@ bool LLAppViewer::initConfiguration()
gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
clp.getOption("settings")[0]);
gSavedSettings.setString("ClientSettingsFile", user_settings_filename);
llinfos << "Using command line specified settings filename: "
<< user_settings_filename << llendl;
LL_INFOS("Settings") << "Using command line specified settings filename: "
<< user_settings_filename << LL_ENDL;
}
// - load overrides from user_settings
@ -2477,8 +2480,8 @@ bool LLAppViewer::initConfiguration()
{
std::string session_settings_filename = clp.getOption("sessionsettings")[0];
gSavedSettings.setString("SessionSettingsFile", session_settings_filename);
llinfos << "Using session settings filename: "
<< session_settings_filename << llendl;
LL_INFOS("Settings") << "Using session settings filename: "
<< session_settings_filename << LL_ENDL;
}
loadSettingsFromDirectory("Session");
@ -2486,8 +2489,8 @@ bool LLAppViewer::initConfiguration()
{
std::string user_session_settings_filename = clp.getOption("usersessionsettings")[0];
gSavedSettings.setString("UserSessionSettingsFile", user_session_settings_filename);
llinfos << "Using user session settings filename: "
<< user_session_settings_filename << llendl;
LL_INFOS("Settings") << "Using user session settings filename: "
<< user_session_settings_filename << LL_ENDL;
}
loadSettingsFromDirectory("UserSession");
@ -2575,9 +2578,13 @@ bool LLAppViewer::initConfiguration()
}
}
if (clp.hasOption("logevents")) {
LLViewerEventRecorder::instance().setEventLoggingOn();
}
std::string CmdLineChannel(gSavedSettings.getString("CmdLineChannel"));
if(! CmdLineChannel.empty())
{
{
LLVersionInfo::resetChannel(CmdLineChannel);
}
@ -2589,16 +2596,16 @@ bool LLAppViewer::initConfiguration()
LLFastTimer::sLog = TRUE;
LLFastTimer::sLogName = std::string("performance");
}
std::string test_name(gSavedSettings.getString("LogMetrics"));
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
// 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;
LLFastTimer::sLogName = test_name;
}
LLFastTimer::sLogName = test_name;
}
if (clp.hasOption("graphicslevel"))
{
@ -2607,14 +2614,14 @@ bool LLAppViewer::initConfiguration()
// that value for validity.
U32 graphicslevel = gSavedSettings.getU32("RenderQualityPerformance");
if (LLFeatureManager::instance().isValidGraphicsLevel(graphicslevel))
{
{
// graphicslevel is valid: save it and engage it later. Capture
// the requested value separately from the settings variable
// because, if this is the first run, LLViewerWindow's constructor
// will call LLFeatureManager::applyRecommendedSettings(), which
// overwrites this settings variable!
mForceGraphicsLevel = graphicslevel;
}
}
}
LLFastTimerView::sAnalyzePerformance = gSavedSettings.getBOOL("AnalyzePerformance");
@ -2645,16 +2652,32 @@ bool LLAppViewer::initConfiguration()
// What can happen is that someone can use IE (or potentially
// other browsers) and do the rough equivalent of command
// injection and steal passwords. Phoenix. SL-55321
LLSLURL start_slurl;
std::string CmdLineLoginLocation(gSavedSettings.getString("CmdLineLoginLocation"));
if(! CmdLineLoginLocation.empty())
{
LLSLURL start_slurl(CmdLineLoginLocation);
{
start_slurl = CmdLineLoginLocation;
LLStartUp::setStartSLURL(start_slurl);
if(start_slurl.getType() == LLSLURL::LOCATION)
{
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");
if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString())
@ -2795,7 +2818,7 @@ bool LLAppViewer::initConfiguration()
LL_DEBUGS("AppInit")<<"set start from NextLoginLocation: "<<nextLoginLocation<<LL_ENDL;
LLStartUp::setStartSLURL(LLSLURL(nextLoginLocation));
}
else if ((clp.hasOption("login") || clp.hasOption("autologin"))
else if ( ( clp.hasOption("login") || clp.hasOption("autologin"))
&& gSavedSettings.getString("CmdLineLoginLocation").empty())
{
// If automatic login from command line with --login switch
@ -3179,7 +3202,7 @@ bool LLAppViewer::initWindow()
LLFeatureManager::getInstance()->setGraphicsLevel(*mForceGraphicsLevel, false);
gSavedSettings.setU32("RenderQualityPerformance", *mForceGraphicsLevel);
}
// Set this flag in case we crash while initializing GL
gSavedSettings.setBOOL("RenderInitError", TRUE);
gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE );

View File

@ -172,21 +172,20 @@ void ll_nvapi_init(NvDRSSessionHandle hSession)
nvapi_error(status);
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)
{
nvapi_error(status);
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

View File

@ -73,6 +73,8 @@
#include "llcallingcard.h"
#include "llslurl.h" // IDEVO
#include "llsidepanelinventory.h"
#include "llavatarname.h"
#include "llagentui.h"
// static
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
void LLAvatarActions::kick(const LLUUID& id)
{

View File

@ -110,6 +110,12 @@ public:
*/
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.
*/

View File

@ -220,18 +220,25 @@ void LLNotificationChiclet::setCounter(S32 counter)
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;
}
if( !(notification->canLogToIM() && notification->hasFormElements())
&& (!notification->getPayload().has("give_inventory_notification")
|| notification->getPayload()["give_inventory_notification"]))
else if( !(notification->canLogToIM() && notification->hasFormElements())
&& (!notification->getPayload().has("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);
}
else if ("request_teleport" == command_name)
{
LLAvatarActions::teleportRequest(selected_conversation_participant_id);
}
else if("add_friend" == command_name)
{
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("im"));
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("chat_history"));
items.push_back(std::string("separator_chat_history"));

View File

@ -0,0 +1,577 @@
/**
* @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 = gAgent.getRegion()->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();
if (session_floater != nearby_chat)
{
widget->setVisibleIfDetached(visible);
}
widget->setVisibleIfDetached(visible);
}
}
}
// Now, do the normal multifloater show/hide
LLMultiFloater::setVisible(visible);
@ -706,13 +706,13 @@ void LLFloaterIMContainer::setVisibleAndFrontmost(BOOL take_focus, const LLSD& k
// Only select other sessions
if (!getSelectedSession().isNull())
{
selectConversationPair(getSelectedSession(), false, take_focus);
selectConversationPair(getSelectedSession(), false, take_focus);
}
if (mInitialized && mIsFirstLaunch)
{
collapseMessagesPane(gSavedPerAccountSettings.getBOOL("ConversationsMessagePaneCollapsed"));
mIsFirstLaunch = false;
}
}
}
void LLFloaterIMContainer::updateResizeLimits()
@ -850,7 +850,7 @@ void LLFloaterIMContainer::assignResizeLimits()
S32 conv_pane_target_width = is_conv_pane_expanded
? ( 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 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);
}
}
gSavedSettings.setU32("ConversationSortOrder", (U32)order);
}
@ -1096,6 +1096,10 @@ void LLFloaterIMContainer::doToParticipants(const std::string& command, uuid_vec
{
LLAvatarActions::offerTeleport(selectedIDS);
}
else if ("request_teleport" == command)
{
LLAvatarActions::teleportRequest(selectedIDS.front());
}
else if ("voice_call" == command)
{
LLAvatarActions::startCall(userID);
@ -1198,7 +1202,7 @@ void LLFloaterIMContainer::doToSelectedConversation(const std::string& command,
}
else if("chat_history" == command)
{
if (selectedIDS.size() > 0)
if (selectedIDS.size() > 0)
{
LLAvatarActions::viewChatHistory(selectedIDS.front());
}
@ -1220,7 +1224,7 @@ void LLFloaterIMContainer::doToSelectedConversation(const std::string& command,
{
LLFloaterReg::showInstance("preview_conversation", LLSD(LLUUID::null), true);
}
}
}
}
}
@ -1251,7 +1255,7 @@ void LLFloaterIMContainer::doToSelectedGroup(const LLSD& userdata)
if (action == "group_profile")
{
LLGroupActions::show(mSelectedSession);
LLGroupActions::show(mSelectedSession);
}
else if (action == "activate_group")
{

View File

@ -2097,7 +2097,6 @@ void LLPanelLandOptions::refresh()
// virtual
void LLPanelLandOptions::draw()
{
refreshSearch(); // Is this necessary? JC
LLPanel::draw();
}
@ -2111,9 +2110,8 @@ void LLPanelLandOptions::refreshSearch()
mCheckShowDirectory->set(FALSE);
mCheckShowDirectory->setEnabled(FALSE);
// *TODO:Translate
const std::string& none_string = LLParcel::getCategoryUIString(LLParcel::C_NONE);
mCategoryCombo->setSimple(none_string);
const std::string& none_string = LLParcel::getCategoryString(LLParcel::C_NONE);
mCategoryCombo->setValue(none_string);
mCategoryCombo->setEnabled(FALSE);
return;
}
@ -2140,10 +2138,9 @@ void LLPanelLandOptions::refreshSearch()
mCheckShowDirectory ->set(show_directory);
// Set by string in case the order in UI doesn't match the order by index.
// *TODO:Translate
LLParcel::ECategory cat = parcel->getCategory();
const std::string& category_string = LLParcel::getCategoryUIString(cat);
mCategoryCombo->setSimple(category_string);
const std::string& category_string = LLParcel::getCategoryString(cat);
mCategoryCombo->setValue(category_string);
std::string tooltip;
bool enable_show_directory = false;

View File

@ -618,9 +618,12 @@ void LLFloaterPreference::cancel()
// hide translation settings floater
LLFloaterReg::hideInstance("prefs_translation");
// hide translation settings floater
// hide autoreplace settings floater
LLFloaterReg::hideInstance("prefs_autoreplace");
// hide spellchecker settings folder
LLFloaterReg::hideInstance("prefs_spellchecker");
// cancel hardware menu
LLFloaterHardwareSettings* hardware_settings = LLFloaterReg::getTypedInstance<LLFloaterHardwareSettings>("prefs_hardware_settings");
if (hardware_settings)

View File

@ -1734,7 +1734,7 @@ void LLPanelEstateInfo::accessAddCore3(const uuid_vec_t& ids, void* data)
LLSD args;
args["NUM_ADDED"] = llformat("%d",ids.size());
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);
LLNotificationsUtil::add("MaxAgentOnRegionBatch", args);
delete change_info;
@ -1750,7 +1750,7 @@ void LLPanelEstateInfo::accessAddCore3(const uuid_vec_t& ids, void* data)
LLSD args;
args["NUM_ADDED"] = llformat("%d",ids.size());
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);
LLNotificationsUtil::add("MaxAgentOnRegionBatch", args);
delete change_info;
@ -2815,9 +2815,10 @@ bool LLDispatchSetEstateAccess::operator()(
}
std::string msg = llformat("Banned residents: (%d, max %d)",
totalBannedAgents,
ESTATE_MAX_ACCESS_IDS);
LLStringUtil::format_map_t args;
args["[BANNEDAGENTS]"] = llformat("%d", totalBannedAgents);
args["[MAXBANNED]"] = llformat("%d", ESTATE_MAX_ACCESS_IDS);
std::string msg = LLTrans::getString("RegionInfoBannedResidents", args);
panel->getChild<LLUICtrl>("ban_resident_label")->setValue(LLSD(msg));
if (banned_agent_name_list)
@ -2837,9 +2838,10 @@ bool LLDispatchSetEstateAccess::operator()(
if (access_flags & ESTATE_ACCESS_MANAGERS)
{
std::string msg = llformat("Estate Managers: (%d, max %d)",
num_estate_managers,
ESTATE_MAX_MANAGERS);
LLStringUtil::format_map_t args;
args["[ESTATEMANAGERS]"] = llformat("%d", num_estate_managers);
args["[MAXMANAGERS]"] = llformat("%d", ESTATE_MAX_MANAGERS);
std::string msg = LLTrans::getString("RegionInfoEstateManagers", args);
panel->getChild<LLUICtrl>("estate_manager_label")->setValue(LLSD(msg));
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
#define LL_LLFLOATERSNAPSHOT_H
#include "llimage.h"
#include "llfloater.h"
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 "lliconctrl.h"
#include "llfloaterreg.h"
#include "llfacebookconnect.h"
#include "lllayoutstack.h"
#include "llpluginclassmedia.h"
#include "llprogressbar.h"
@ -46,7 +47,8 @@ LLFloaterWebContent::_Params::_Params()
id("id"),
window_class("window_class", "web_content"),
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"),
trusted_content("trusted_content", false),
show_page_title("show_page_title", true)
@ -65,7 +67,11 @@ LLFloaterWebContent::LLFloaterWebContent( const Params& params )
mBtnReload(NULL),
mBtnStop(NULL),
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.Forward", boost::bind( &LLFloaterWebContent::onClickForward, this ));
@ -97,7 +103,7 @@ BOOL LLFloaterWebContent::postBuild()
// cache image for secure browsing
mSecureLockIcon = getChild< LLIconCtrl >("media_secure_lock_flag");
// initialize the URL history using the system URL History manager
initializeURLHistory();
@ -243,6 +249,7 @@ void LLFloaterWebContent::open_media(const Params& p)
getChild<LLLayoutPanel>("status_bar")->setVisible(p.show_chrome);
getChild<LLLayoutPanel>("nav_controls")->setVisible(p.show_chrome);
bool address_entry_enabled = p.allow_address_entry && !p.trusted_content;
mAllowNavigation = p.allow_back_forward_navigation;
getChildView("address")->setEnabled(address_entry_enabled);
getChildView("popexternal")->setEnabled(address_entry_enabled);
@ -287,6 +294,16 @@ void LLFloaterWebContent::onOpen(const LLSD& key)
//virtual
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);
destroy();
}
@ -295,8 +312,11 @@ void LLFloaterWebContent::onClose(bool app_quitting)
void LLFloaterWebContent::draw()
{
// this is asynchronous so we need to keep checking
mBtnBack->setEnabled( mWebBrowser->canNavigateBack() );
mBtnForward->setEnabled( mWebBrowser->canNavigateForward() );
mBtnBack->setEnabled( mWebBrowser->canNavigateBack() && mAllowNavigation);
mBtnForward->setEnabled( mWebBrowser->canNavigateForward() && mAllowNavigation);
// Show/hide the lock icon
mSecureLockIcon->setVisible(mSecureURL && !mAddressCombo->hasFocus());
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
const std::string end_str = "";
mStatusBarText->setText( end_str );
// decide if secure browsing icon should be displayed
std::string prefix = std::string("https://");
std::string test_prefix = mCurrentURL.substr(0, prefix.length());
LLStringUtil::toLower(test_prefix);
if(test_prefix == prefix)
{
mSecureLockIcon->setVisible(true);
mAddressCombo->setLeftTextPadding(22);
}
else
{
mSecureLockIcon->setVisible(false);
mAddressCombo->setLeftTextPadding(2);
}
}
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)
{
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
LLURLHistory::removeURL("browser", mCurrentURL);
LLURLHistory::addURL("browser", mCurrentURL);
// Update current URL
mCurrentURL = url;
LLStringUtil::trim(mCurrentURL);
mAddressCombo->remove( mCurrentURL );
mAddressCombo->add( mCurrentURL );
mAddressCombo->selectByValue( mCurrentURL );
// Serialize url history into the system URL History manager
LLURLHistory::removeURL("browser", 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()
@ -451,6 +483,7 @@ void LLFloaterWebContent::onEnterAddress()
// make sure there is at least something there.
// (perhaps this test should be for minimum length of a URL)
std::string url = mAddressCombo->getValue().asString();
LLStringUtil::trim(url);
if ( url.length() > 0 )
{
mWebBrowser->navigateTo( url, "text/html");
@ -462,6 +495,7 @@ void LLFloaterWebContent::onPopExternal()
// make sure there is at least something there.
// (perhaps this test should be for minimum length of a URL)
std::string url = mAddressCombo->getValue().asString();
LLStringUtil::trim(url);
if ( url.length() > 0 )
{
LLWeb::loadURLExternal( url );

View File

@ -55,6 +55,7 @@ public:
id;
Optional<bool> show_chrome,
allow_address_entry,
allow_back_forward_navigation,
trusted_content,
show_page_title;
Optional<LLRect> preferred_media_size;
@ -106,9 +107,12 @@ protected:
LLView* mBtnReload;
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;
bool mShowPageTitle;
bool mAllowNavigation;
bool mSecureURL; // true when the current url is prefixed "https://"
};
#endif // LL_LLFLOATERWEBCONTENT_H

View File

@ -130,10 +130,10 @@ void process_dnd_im(const LLSD& notification)
fromID,
false,
false); //will need slight refactor to retrieve whether offline message or not (assume online for now)
}
}
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)
{
std::string user_preferences;
std::string user_preferences;
LLUUID participant_id = msg[is_dnd_msg ? "FROM_ID" : "from_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
if (gAgent.getID() == participant_id)
{
return;
}
// do not show notification which goes from agent
if (gAgent.getID() == participant_id)
{
return;
}
// determine state of conversations floater
enum {CLOSED, NOT_ON_TOP, ON_TOP, ON_TOP_AND_ITEM_IS_SELECTED} conversations_floater_status;
// determine state of conversations floater
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);
bool store_dnd_message = false; // flag storage of a dnd message
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;
}
else if (!im_box->hasFocus() &&
!(session_floater && LLFloater::isVisible(session_floater)
&& !session_floater->isMinimized() && session_floater->hasFocus()))
!(session_floater && LLFloater::isVisible(session_floater)
&& !session_floater->isMinimized() && session_floater->hasFocus()))
{
conversations_floater_status = NOT_ON_TOP;
}
else if (im_box->getSelectedSession() != session_id)
{
conversations_floater_status = ON_TOP;
}
}
else
{
conversations_floater_status = ON_TOP_AND_ITEM_IS_SELECTED;
}
// determine user prefs for this session
if (session_id.isNull())
{
// determine user prefs for this session
if (session_id.isNull())
{
if (msg["source_type"].asInteger() == CHAT_SOURCE_OBJECT)
{
user_preferences = gSavedSettings.getString("NotificationObjectIMOptions");
@ -206,50 +206,50 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)
}
else
{
user_preferences = gSavedSettings.getString("NotificationNearbyChatOptions");
user_preferences = gSavedSettings.getString("NotificationNearbyChatOptions");
if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNearbyChatIM") == TRUE))
{
make_ui_sound("UISndNewIncomingIMSession");
}
}
}
}
else if(session->isP2PSessionType())
{
if (LLAvatarTracker::instance().isBuddy(participant_id))
{
user_preferences = gSavedSettings.getString("NotificationFriendIMOptions");
else if(session->isP2PSessionType())
{
if (LLAvatarTracker::instance().isBuddy(participant_id))
{
user_preferences = gSavedSettings.getString("NotificationFriendIMOptions");
if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundFriendIM") == TRUE))
{
make_ui_sound("UISndNewIncomingIMSession");
}
}
else
{
user_preferences = gSavedSettings.getString("NotificationNonFriendIMOptions");
}
else
{
user_preferences = gSavedSettings.getString("NotificationNonFriendIMOptions");
if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNonFriendIM") == TRUE))
{
make_ui_sound("UISndNewIncomingIMSession");
}
}
}
}
}
else if(session->isAdHocSessionType())
{
user_preferences = gSavedSettings.getString("NotificationConferenceIMOptions");
else if(session->isAdHocSessionType())
{
user_preferences = gSavedSettings.getString("NotificationConferenceIMOptions");
if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundConferenceIM") == TRUE))
{
make_ui_sound("UISndNewIncomingIMSession");
}
}
}
else if(session->isGroupSessionType())
{
user_preferences = gSavedSettings.getString("NotificationGroupChatOptions");
else if(session->isGroupSessionType())
{
user_preferences = gSavedSettings.getString("NotificationGroupChatOptions");
if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundGroupChatIM") == TRUE))
{
make_ui_sound("UISndNewIncomingIMSession");
}
}
}
// actions:
// actions:
// 0. nothing - exit
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;
}
}
}
}
// 2. Flash line item
if ("openconversations" == user_preferences
|| ON_TOP == conversations_floater_status
|| ("toast" == user_preferences && ON_TOP != conversations_floater_status)
// 2. Flash line item
if ("openconversations" == user_preferences
|| ON_TOP == conversations_floater_status
|| ("toast" == user_preferences && ON_TOP != conversations_floater_status)
|| ("flash" == user_preferences && (CLOSED == conversations_floater_status
|| NOT_ON_TOP == conversations_floater_status))
|| is_dnd_msg)
{
if(!LLMuteList::getInstance()->isMuted(participant_id))
{
{
if(!LLMuteList::getInstance()->isMuted(participant_id))
{
if(gAgent.isDoNotDisturb())
{
store_dnd_message = true;
@ -318,43 +318,43 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)
}
else
{
im_box->flashConversationItemWidget(session_id, true);
}
}
im_box->flashConversationItemWidget(session_id, true);
}
}
}
}
// 3. Flash FUI button
if (("toast" == user_preferences || "flash" == user_preferences) &&
(CLOSED == conversations_floater_status
// 3. Flash FUI button
if (("toast" == user_preferences || "flash" == user_preferences) &&
(CLOSED == conversations_floater_status
|| NOT_ON_TOP == conversations_floater_status)
&& !is_session_focused
&& !is_dnd_msg) //prevent flashing FUI button because the conversation floater will have already opened
{
if(!LLMuteList::getInstance()->isMuted(participant_id))
{
{
if(!gAgent.isDoNotDisturb())
{
{
gToolBarView->flashCommand(LLCommandId("chat"), true, im_box->isMinimized());
}
}
else
{
store_dnd_message = true;
}
}
}
}
// 4. Toast
if ((("toast" == user_preferences) &&
// 4. Toast
if ((("toast" == user_preferences) &&
(ON_TOP_AND_ITEM_IS_SELECTED != conversations_floater_status) &&
(!session_floater->isTornOff() || !LLFloater::isVisible(session_floater)))
|| !session_floater->isMessagePaneExpanded())
|| !session_floater->isMessagePaneExpanded())
{
//Show IM toasts (upper right toasts)
// Skip toasting for system messages and for nearby chat
if(session_id.notNull() && participant_id.notNull())
{
{
//Show IM toasts (upper right toasts)
// Skip toasting for system messages and for nearby chat
if(session_id.notNull() && participant_id.notNull())
{
if(!is_dnd_msg)
{
if(gAgent.isDoNotDisturb())
@ -363,10 +363,10 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)
}
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)
{

View File

@ -4739,6 +4739,16 @@ void LLCallingCardBridge::performAction(LLInventoryModel* model, std::string act
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);
}
@ -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"));
items.push_back(std::string("Offer Teleport..."));
items.push_back(std::string("Request Teleport..."));
items.push_back(std::string("Conference Chat"));
if (!good_card)
@ -4834,6 +4845,7 @@ void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
if (!good_card || !user_online)
{
disabled_items.push_back(std::string("Offer Teleport..."));
disabled_items.push_back(std::string("Request Teleport..."));
disabled_items.push_back(std::string("Conference Chat"));
}
}

View File

@ -343,8 +343,11 @@ void LLNetMap::draw()
// Draw avatars
for (U32 i = 0; i < avatar_ids.size(); i++)
{
pos_map = globalPosToView(positions[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);

View File

@ -35,6 +35,9 @@
#include "llnotificationmanager.h"
#include "llnotifications.h"
#include "llscriptfloater.h"
#include "llfacebookconnect.h"
#include "llavatarname.h"
#include "llavatarnamecache.h"
using namespace LLNotificationsUI;
@ -87,7 +90,7 @@ bool LLScriptHandler::processNotification(const LLNotificationPtr& notification)
{
LLScriptFloaterManager::getInstance()->onAddNotification(notification->getID());
}
else
else if (notification->canShowToast())
{
LLToastPanel* notify_box = LLToastPanel::buidPanelFromNotification(notification);

View File

@ -28,6 +28,8 @@
// libs
#include "llavatarname.h"
#include "llconversationview.h"
#include "llfloaterimcontainer.h"
#include "llfloaterreg.h"
#include "llfloatersidepanelcontainer.h"
#include "llmenubutton.h"
@ -48,15 +50,19 @@
#include "llavataractions.h"
#include "llavatarlist.h"
#include "llavatarlistitem.h"
#include "llavatarnamecache.h"
#include "llcallingcard.h" // for LLAvatarTracker
#include "llcallbacklist.h"
#include "llerror.h"
#include "llfacebookconnect.h"
#include "llfloateravatarpicker.h"
//#include "llfloaterminiinspector.h"
#include "llfriendcard.h"
#include "llgroupactions.h"
#include "llgrouplist.h"
#include "llinventoryobserver.h"
#include "llnetmap.h"
#include "llpanelpeoplemenus.h"
#include "llparticipantlist.h"
#include "llsidetraypanelcontainer.h"
#include "llrecentpeople.h"
#include "llviewercontrol.h" // for gSavedSettings
@ -64,6 +70,10 @@
#include "llvoiceclient.h"
#include "llworld.h"
#include "llspeakers.h"
#include "llfloaterwebcontent.h"
#include "llagentui.h"
#include "llslurl.h"
#define FRIEND_LIST_UPDATE_TIMEOUT 0.5
#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 RECENT_TAB_NAME = "recent_panel";
static const std::string BLOCKED_TAB_NAME = "blocked_panel"; // blocked avatars
static const std::string COLLAPSED_BY_USER = "collapsed_by_user";
extern S32 gMaxAgentGroups;
/** Comparator for comparing avatar items by last interaction date */
@ -495,6 +505,7 @@ public:
LLPanelPeople::LLPanelPeople()
: LLPanel(),
mTryToConnectToFbc(true),
mTabContainer(NULL),
mOnlineFriendList(NULL),
mAllFriendList(NULL),
@ -573,6 +584,7 @@ BOOL LLPanelPeople::postBuild()
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>("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->setCommitCallback(boost::bind(&LLPanelPeople::onTabSelected, this, _2));
@ -583,8 +595,11 @@ BOOL LLPanelPeople::postBuild()
// updater is active only if panel is visible to user.
friends_tab->setVisibleCallback(boost::bind(&Updater::setActive, mFriendListUpdater, _2));
friends_tab->setVisibleCallback(boost::bind(&LLPanelPeople::removePicker, this));
friends_tab->setVisibleCallback(boost::bind(&LLPanelPeople::updateFacebookList, this, _2));
mOnlineFriendList = friends_tab->getChild<LLAvatarList>("avatars_online");
mAllFriendList = friends_tab->getChild<LLAvatarList>("avatars_all");
mSuggestedFriends = friends_tab->getChild<LLAvatarList>("suggested_friends");
mOnlineFriendList->setNoItemsCommentText(getString("no_friends_online"));
mOnlineFriendList->setShowIcons("FriendsListShowIcons");
mOnlineFriendList->showPermissions("FriendsListShowPermissions");
@ -617,6 +632,7 @@ BOOL LLPanelPeople::postBuild()
mRecentList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu);
mAllFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu);
mOnlineFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu);
mSuggestedFriends->setContextMenu(&LLPanelPeopleMenus::gSuggestedFriendsContextMenu);
setSortOrder(mRecentList, (ESortOrder)gSavedSettings.getU32("RecentPeopleSortOrder"), 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...)
// 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);
if (no_friends_text->getVisible())
{
@ -762,9 +778,40 @@ void LLPanelPeople::updateFriendList()
mAllFriendList->setDirty(true, !mAllFriendList->filterHasMatches());
//update trash and other buttons according to a selected item
updateButtons();
updateSuggestedFriendList();
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()
{
if (!mNearbyList)
@ -788,6 +835,51 @@ void LLPanelPeople::updateRecentList()
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()
{
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
if (!saved_filter.empty())
{
notifyChildren(LLSD().with("action","store_state"));
}
{
notifyChildren(LLSD().with("action","store_state"));
}
mOnlineFriendList->setNameFilter(filter);
mAllFriendList->setNameFilter(filter);
mSuggestedFriends->setNameFilter(filter);
setAccordionCollapsedByUser("tab_online", false);
setAccordionCollapsedByUser("tab_all", false);
showFriendsAccordionsIfNeeded();
setAccordionCollapsedByUser("tab_online", false);
setAccordionCollapsedByUser("tab_all", false);
setAccordionCollapsedByUser("tab_suggested_friends", false);
showFriendsAccordionsIfNeeded();
// restore accordion tabs state _after_ all manipulations
if(saved_filter.empty())
{
notifyChildren(LLSD().with("action","restore_state"));
}
}
{
notifyChildren(LLSD().with("action","restore_state"));
}
}
else if (cur_tab == GROUP_TAB_NAME)
{
mGroupList->setNameFilter(filter);
@ -1229,7 +1323,7 @@ void LLPanelPeople::onFriendsViewSortMenuItemClicked(const LLSD& userdata)
mAllFriendList->showPermissions(show_permissions);
mOnlineFriendList->showPermissions(show_permissions);
}
}
}
void LLPanelPeople::onGroupsViewSortMenuItemClicked(const LLSD& userdata)
{
@ -1387,6 +1481,7 @@ void LLPanelPeople::showFriendsAccordionsIfNeeded()
// Expand and show accordions if needed, else - hide them
showAccordion("tab_online", mOnlineFriendList->filterHasMatches());
showAccordion("tab_all", mAllFriendList->filterHasMatches());
showAccordion("tab_suggested_friends", mSuggestedFriends->filterHasMatches());
// Rearrange accordions
LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("friends_accordion");
@ -1450,4 +1545,5 @@ bool LLPanelPeople::isAccordionCollapsedByUser(const std::string& name)
return isAccordionCollapsedByUser(getChild<LLUICtrl>(name));
}
// EOF

View File

@ -22,7 +22,7 @@
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
*/
#ifndef LL_LLPANELPEOPLE_H
#define LL_LLPANELPEOPLE_H
@ -30,6 +30,7 @@
#include <llpanel.h>
#include "llcallingcard.h" // for avatar tracker
#include "llfloaterwebcontent.h"
#include "llvoiceclient.h"
class LLAvatarList;
@ -55,6 +56,8 @@ public:
// when voice is available
/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
bool mTryToConnectToFbc;
// internals
class Updater;
@ -73,8 +76,10 @@ private:
// methods indirectly called by the updaters
void updateFriendListHelpText();
void updateFriendList();
bool updateSuggestedFriendList();
void updateNearbyList();
void updateRecentList();
void updateFacebookList(bool visible);
bool isItemsFreeOfFriends(const uuid_vec_t& uuids);
@ -121,6 +126,8 @@ private:
void onFriendListRefreshComplete(LLUICtrl*ctrl, const LLSD& param);
bool onConnectedToFacebook(const LLSD& data);
void setAccordionCollapsedByUser(LLUICtrl* acc_tab, bool collapsed);
void setAccordionCollapsedByUser(const std::string& name, bool collapsed);
bool isAccordionCollapsedByUser(LLUICtrl* acc_tab);
@ -129,6 +136,7 @@ private:
LLTabContainer* mTabContainer;
LLAvatarList* mOnlineFriendList;
LLAvatarList* mAllFriendList;
LLAvatarList* mSuggestedFriends;
LLAvatarList* mNearbyList;
LLAvatarList* mRecentList;
LLGroupList* mGroupList;
@ -140,6 +148,7 @@ private:
Updater* mFriendListUpdater;
Updater* mNearbyListUpdater;
Updater* mRecentListUpdater;
Updater* mFacebookListUpdater;
Updater* mButtonsUpdater;
LLHandle< LLFloater > mPicker;
};

View File

@ -47,6 +47,7 @@ namespace LLPanelPeopleMenus
PeopleContextMenu gPeopleContextMenu;
NearbyPeopleContextMenu gNearbyPeopleContextMenu;
SuggestedFriendsContextMenu gSuggestedFriendsContextMenu;
//== PeopleContextMenu ===============================================================
@ -74,6 +75,7 @@ LLContextMenu* PeopleContextMenu::createMenu()
registrar.add("Avatar.Pay", boost::bind(&LLAvatarActions::pay, id));
registrar.add("Avatar.BlockUnblock", boost::bind(&LLAvatarActions::toggleBlock, 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));
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("im"));
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("chat_history"));
items.push_back(std::string("separator_chat_history"));
@ -255,6 +258,13 @@ bool PeopleContextMenu::checkContextMenuItem(const LLSD& userdata)
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()
{
// 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("im"));
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("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);
}
//== 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

View File

@ -47,6 +47,7 @@ private:
bool enableContextMenuItem(const LLSD& userdata);
bool checkContextMenuItem(const LLSD& userdata);
void offerTeleport();
void requestTeleport();
};
/**
@ -58,8 +59,21 @@ protected:
/*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 NearbyPeopleContextMenu gNearbyPeopleContextMenu;
extern SuggestedFriendsContextMenu gSuggestedFriendsContextMenu;
} // namespace LLPanelPeopleMenus

View File

@ -94,7 +94,8 @@ LLPanelPrimMediaControls::LLPanelPrimMediaControls() :
mZoomObjectFace(0),
mVolumeSliderVisible(0),
mWindowShade(NULL),
mHideImmediately(false)
mHideImmediately(false),
mSecureURL(false)
{
mCommitCallbackRegistrar.add("MediaCtrl.Close", boost::bind(&LLPanelPrimMediaControls::onClickClose, this));
mCommitCallbackRegistrar.add("MediaCtrl.Back", boost::bind(&LLPanelPrimMediaControls::onClickBack, this));
@ -345,7 +346,7 @@ void LLPanelPrimMediaControls::updateShape()
// Disable zoom if HUD
mZoomCtrl->setEnabled(!is_hud);
mUnzoomCtrl->setEnabled(!is_hud);
mSecureLockIcon->setVisible(false);
mSecureURL = false;
mCurrentURL = media_impl->getCurrentMediaURL();
mBackCtrl->setEnabled((media_impl != NULL) && media_impl->canNavigateBack() && can_navigate);
@ -382,7 +383,7 @@ void LLPanelPrimMediaControls::updateShape()
mVolumeSliderCtrl->setVisible(has_focus && shouldVolumeSliderBeVisible());
mWhitelistIcon->setVisible(false);
mSecureLockIcon->setVisible(false);
mSecureURL = false;
if (mMediaPanelScroll)
{
mMediaPanelScroll->setVisible(false);
@ -416,7 +417,7 @@ void LLPanelPrimMediaControls::updateShape()
mMediaPlaySliderCtrl->setEnabled(true);
}
// video vloume
// video volume
if(volume <= 0.0)
{
mMuteBtn->setToggleState(true);
@ -492,10 +493,8 @@ void LLPanelPrimMediaControls::updateShape()
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(has_focus);
}
mSecureURL = has_focus && (test_prefix == prefix);
mCurrentURL = (mSecureURL ? " " + mCurrentURL : mCurrentURL);
if(mCurrentURL!=mPreviousURL)
{
@ -746,6 +745,9 @@ void LLPanelPrimMediaControls::draw()
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
// Assumes layout_stack is a direct child of this panel

View File

@ -191,6 +191,7 @@ private:
bool mUpdateSlider;
bool mClearFaceOnFade;
bool mHideImmediately;
bool mSecureURL;
LLMatrix4 mLastCameraMat;
EZoomLevel mCurrentZoom;

View File

@ -27,6 +27,7 @@
#include "llviewerprecompiledheaders.h"
#include "llavatarnamecache.h"
#include "llerror.h"
#include "llimview.h"
#include "llfloaterimcontainer.h"
#include "llparticipantlist.h"
@ -401,6 +402,8 @@ void LLParticipantList::addAvatarIDExceptAgent(const LLUUID& avatar_id)
adjustParticipant(avatar_id);
}
static LLFastTimer::DeclareTimer FTM_FOLDERVIEW_TEST("add test avatar agents");
void LLParticipantList::adjustParticipant(const LLUUID& 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;
}
@ -268,6 +269,8 @@ LLSD _ext_key_usage_ext(X509* cert)
ASN1_OBJECT_free(usage);
}
}
EXTENDED_KEY_USAGE_free( eku );
}
return result;
}
@ -280,6 +283,8 @@ LLSD _subject_key_identifier_ext(X509 *cert)
if(skeyid)
{
result = cert_string_from_octet_string(skeyid);
ASN1_OCTET_STRING_free( skeyid );
}
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);
}
AUTHORITY_KEYID_free( akeyid );
}
// 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));
}
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);
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()

View File

@ -55,6 +55,7 @@ public:
// Operating with items
void removeItemByID(const LLUUID& id);
LLPanel * findItemByID(const LLUUID& id);
// Operating with outfit
virtual void setVisible(BOOL visible);

View File

@ -93,7 +93,7 @@ LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) : LLToastPanel(p.notif
if(!mIsGroupMsg)
{
mAvatarName->setValue(p.from);
mAvatarName->setValue(p.from);
}
mTime->setValue(p.time);
mSessionID = p.session_id;
@ -164,7 +164,7 @@ void LLToastIMPanel::spawnNameToolTip()
params.background_visible(false);
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
{

View File

@ -103,22 +103,29 @@ LLSD LLURLHistory::getURLHistory(const std::string& collection)
// static
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);
}
}
// static
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)
{
sHistorySD[collection].erase(index);
}
}
LLURI u(url);
std::string simplified_url = u.scheme() + "://" + u.authority() + u.path();
for(int index = 0; index < sHistorySD[collection].size(); index++)
{
if(sHistorySD[collection].get(index).asString() == simplified_url)
{
sHistorySD[collection].erase(index);
}
}
}
}
// static

View File

@ -103,6 +103,7 @@
#include "llfloatersettingsdebug.h"
#include "llfloatersidepanelcontainer.h"
#include "llfloatersnapshot.h"
#include "llfloatersocial.h"
#include "llfloatersounddevices.h"
#include "llfloaterspellchecksettings.h"
#include "llfloatertelehub.h"
@ -303,6 +304,7 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("sell_land", "floater_sell_land.xml", &LLFloaterSellLand::buildFloater);
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("social", "floater_social.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSocial>);
LLFloaterReg::add("stats", "floater_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloater>);
LLFloaterReg::add("start_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRunQueue>);
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("profile", "floater_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::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();
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
// 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];
}

View File

@ -2000,7 +2000,12 @@ void LLViewerMediaImpl::loadURI()
"<>#%"
";/?:@&=",
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 );
@ -2567,7 +2572,12 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi
if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
{
// 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.
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()
{
// 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)
{

View File

@ -40,11 +40,13 @@
#include "llinventorypanel.h"
#include "llnotifications.h"
#include "llnotificationsutil.h"
#include "llviewereventrecorder.h"
// newview includes
#include "llagent.h"
#include "llagentaccess.h"
#include "llagentcamera.h"
#include "llagentui.h"
#include "llagentwearables.h"
#include "llagentpilot.h"
#include "llcompilequeue.h"
@ -52,6 +54,7 @@
#include "lldaycyclemanager.h"
#include "lldebugview.h"
#include "llenvmanager.h"
#include "llfacebookconnect.h"
#include "llfilepicker.h"
#include "llfirstuse.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 //
@ -8420,6 +8460,8 @@ void initialize_menus()
// Don't prepend MenuName.Foo because these can be used in any menu.
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");
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 LLAdvancedToggleAgentPilotLoop(), "Advanced.ToggleAgentPilotLoop");
view_listener_t::addMenu(new LLAdvancedCheckAgentPilotLoop(), "Advanced.CheckAgentPilotLoop");
view_listener_t::addMenu(new LLAdvancedViewerEventRecorder(), "Advanced.EventRecorder");
// Advanced > Debugging
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_DECLINED:
case IM_GODLIKE_LURE_USER:
case IM_YET_TO_BE_USED:
case IM_TELEPORT_REQUEST:
case IM_GROUP_ELECTION_DEPRECATED:
//IM_GOTO_URL
//IM_FROM_TASK_AS_ALERT
@ -2989,6 +2989,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
break;
case IM_LURE_USER:
case IM_TELEPORT_REQUEST:
{
if (is_muted)
{
@ -3011,7 +3012,8 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
bool canUserAccessDstRegion = true;
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_icn = LLViewerRegion::getAccessIcon(region_access);
@ -3083,12 +3085,22 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
}
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.payload = payload;
LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false);
}
}
}
break;
@ -6866,6 +6878,51 @@ void send_group_notice(const LLUUID& group_id,
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)
{
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);
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);
if(0 == option)
{
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;
LLNotificationsUtil::add("TeleportOfferSent", args, payload);
// Add the recepient to the recent people list.
LLRecentPeople::instance().add(target_id);
}
}
gAgent.sendReliableMessage();
send_lures(notification, response);
}
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,
const std::string& name,

View File

@ -954,15 +954,17 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
objectp = *idle_iter;
llassert(objectp->isActive());
objectp->idleUpdate(agent, world, frame_time);
}
}
//update flexible objects
LLVolumeImplFlexible::updateClass();
//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("EstateChangeInfo");
capabilityNames.append("EventQueueGet");
capabilityNames.append("FacebookConnect");
//capabilityNames.append("FacebookRedirect");
if (gSavedSettings.getBOOL("UseHTTPInventory"))
{

View File

@ -198,6 +198,8 @@
#include "llagentui.h"
#include "llwearablelist.h"
#include "llviewereventrecorder.h"
#include "llnotifications.h"
#include "llnotificationsutil.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;
}
return mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down);
}
// Topmost view gets a chance before the hierarchy
//LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
//if (top_ctrl)
//{
// S32 local_x, local_y;
// top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
// if (top_ctrl->pointInView(local_x, local_y))
// {
// return top_ctrl->handleAnyMouseClick(local_x, local_y, mask, clicktype, down) ;
// }
// else
// {
// if (down)
// {
// gFocusMgr.setTopCtrl(NULL);
// }
// }
//}
BOOL r = mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down);
if (r) {
lldebugs << "LLViewerWindow::handleAnyMouseClick viewer with mousecaptor calling updatemouseeventinfo - local_x|global x "<< local_x << " " << x << "local/global y " << local_y << " " << y << llendl;
LLViewerEventRecorder::instance().setMouseGlobalCoords(x,y);
LLViewerEventRecorder::instance().logMouseEvent(std::string(buttonstatestr),std::string(buttonname));
}
return r;
}
// Mark the click as handled and return if we aren't within the root view to avoid spurious bugs
if( !mRootView->pointInView(x, y) )
@ -982,27 +975,44 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK
return TRUE;
}
// 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)
{
llinfos << buttonname << " Mouse " << buttonstatestr << " " << LLView::sMouseHandlerMessage << llendl;
}
llinfos << buttonname << " Mouse " << buttonstatestr << " " << LLViewerEventRecorder::instance().get_xui() << llendl;
}
return TRUE;
}
else if (LLView::sDebugMouseHandling)
{
llinfos << buttonname << " Mouse " << buttonstatestr << " not handled by view" << llendl;
}
} else if (LLView::sDebugMouseHandling)
{
llinfos << buttonname << " Mouse " << buttonstatestr << " not handled by view" << llendl;
}
}
// Do not allow tool manager to handle mouseclicks if we have disconnected
if(!gDisconnected && LLToolMgr::getInstance()->getCurrentTool()->handleAnyMouseClick( x, y, mask, clicktype, down ) )
{
LLViewerEventRecorder::instance().clear_xui();
return TRUE;
}
// 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.
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)
{
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))
||(gMenuHolder && gMenuHolder->handleKey(key, mask, TRUE)))
{
lldebugs << "LLviewerWindow::handleKey handle nav keys for nav" << llendl;
LLViewerEventRecorder::instance().logKeyEvent(key,mask);
return TRUE;
}
@ -2533,12 +2546,14 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
&& keyboard_focus
&& keyboard_focus->handleKey(key,mask,FALSE))
{
LLViewerEventRecorder::instance().logKeyEvent(key,mask);
return TRUE;
}
if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask))
||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask)))
{
LLViewerEventRecorder::instance().logKeyEvent(key,mask);
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 (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 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();
}
LLViewerEventRecorder::instance().logKeyEvent(key,mask);
return TRUE;
}
// hidden edit menu for cut/copy/paste
if (gEditMenu && gEditMenu->handleAcceleratorKey(key, mask))
{
LLViewerEventRecorder::instance().logKeyEvent(key,mask);
return TRUE;
}
@ -2606,18 +2624,27 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
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;
} 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) )
{
lldebugs << "LLviewerWindow::handleKey toolbar handling?" << llendl;
LLViewerEventRecorder::instance().logKeyEvent(key,mask);
return TRUE;
}
// Try for a new-format gesture
if (LLGestureMgr::instance().triggerGesture(key, mask))
{
lldebugs << "LLviewerWindow::handleKey new gesture feature" << llendl;
LLViewerEventRecorder::instance().logKeyEvent(key,mask);
return TRUE;
}
@ -2625,6 +2652,8 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
// don't pass it down to the menus.
if (gGestureList.trigger(key, mask))
{
lldebugs << "LLviewerWindow::handleKey check gesture trigger" << llendl;
LLViewerEventRecorder::instance().logKeyEvent(key,mask);
return TRUE;
}
@ -2673,7 +2702,7 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
// HACK: Numeric keypad <enter> on Mac is Unicode 3
// HACK: Control-M on Windows is Unicode 13
if ((uni_char == 13 && mask != MASK_CONTROL)
|| (uni_char == 3 && mask == MASK_NONE))
|| (uni_char == 3 && mask == MASK_NONE) )
{
if (mask != MASK_ALT)
{
@ -2696,14 +2725,7 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
return TRUE;
}
//// Topmost view gets a chance before the hierarchy
//LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
//if (top_ctrl && top_ctrl->handleUnicodeChar( uni_char, FALSE ) )
//{
// return TRUE;
//}
return TRUE;
return TRUE;
}
return FALSE;
@ -2712,8 +2734,6 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
void LLViewerWindow::handleScrollWheel(S32 clicks)
{
LLView::sMouseHandlerMessage.clear();
LLUI::resetMouseIdleTimer();
LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();

View File

@ -148,9 +148,6 @@ public:
LL_DEBUGS("Snapshots") << "Uploading image succeeded. Response: [" << body << "]" << llendl;
LLWebProfile::reportImageUploadStatus(true);
}
private:
LLPointer<LLImageFormatted> mImagep;
};
@ -172,7 +169,7 @@ public:
headers["Cookie"] = LLWebProfile::getAuthCookie();
const std::string& redir_url = content["location"];
LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << llendl;
LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder, headers);
LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder(), headers);
}
else
{

View File

@ -265,7 +265,9 @@ void LLWindowListener::getPaths(LLSD const & request)
void LLWindowListener::keyDown(LLSD const & evt)
{
Response response(LLSD(), evt);
KEY key = getKEY(evt);
MASK mask = getMask(evt);
if (evt.has("path"))
{
std::string path(evt["path"]);
@ -280,8 +282,6 @@ void LLWindowListener::keyDown(LLSD const & evt)
response.setResponse(target_view->getInfo());
gFocusMgr.setKeyboardFocus(target_view);
KEY key = getKEY(evt);
MASK mask = getMask(evt);
gViewerKeyboard.handleKey(key, mask, false);
if(key < 0x80) mWindow->handleUnicodeChar(key, mask);
}
@ -294,7 +294,8 @@ void LLWindowListener::keyDown(LLSD const & evt)
}
else
{
mKbGetter()->handleTranslatedKeyDown(getKEY(evt), getMask(evt));
gViewerKeyboard.handleKey(key, mask, false);
if(key < 0x80) mWindow->handleUnicodeChar(key, mask);
}
}

View File

@ -518,17 +518,21 @@ bool LLWorldMap::insertItem(U32 x_world, U32 y_world, std::string& name, LLUUID&
case MAP_ITEM_LAND_FOR_SALE: // land for sale
case MAP_ITEM_LAND_FOR_SALE_ADULT: // adult land for sale
{
F32 cost_per_sqm = 0.0f;
if ((F32)extra > 0)
{
cost_per_sqm = (F32)extra2 / (F32)extra;
}
static LLUIString tooltip_fmt = LLTrans::getString("worldmap_item_tooltip_format");
tooltip_fmt.setArg("[AREA]", llformat("%d", extra));
tooltip_fmt.setArg("[PRICE]", llformat("%d", extra2));
tooltip_fmt.setArg("[PRICE_PER_SQM]", llformat("%.1f", cost_per_sqm));
// Check for division by zero
if (extra != 0)
{
tooltip_fmt.setArg("[SQMPRICE]", llformat("%.1f", (F32)extra2 / (F32)extra));
}
else
{
tooltip_fmt.setArg("[SQMPRICE]", LLTrans::getString("Unknown"));
}
new_item.setTooltip(tooltip_fmt.getString());
if (type == MAP_ITEM_LAND_FOR_SALE)

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -148,6 +148,7 @@ with the same filename but different name
<texture name="Command_Preferences_Icon" file_name="toolbar_icons/preferences.png" preload="true" />
<texture name="Command_Profile_Icon" file_name="toolbar_icons/profile.png" preload="true" />
<texture name="Command_Search_Icon" file_name="toolbar_icons/search.png" preload="true" />
<texture name="Command_Social_Icon" file_name="toolbar_icons/facebook.png" preload="true" />
<texture name="Command_Snapshot_Icon" file_name="toolbar_icons/snapshot.png" preload="true" />
<texture name="Command_Speak_Icon" file_name="toolbar_icons/speak.png" preload="true" />
<texture name="Command_View_Icon" file_name="toolbar_icons/view.png" preload="true" />
@ -202,6 +203,8 @@ with the same filename but different name
<texture name="ExternalBrowser_Off" file_name="icons/ExternalBrowser_Off.png" preload="false" />
<texture name="Edit_Wrench" file_name="icons/Edit_Wrench.png" preload="false" />
<texture name="Facebook_Icon" file_name="icons/Facebook.png" preload="false" />
<texture name="Favorite_Star_Active" file_name="navbar/Favorite_Star_Active.png" preload="false" />
<texture name="Favorite_Star_Off" file_name="navbar/Favorite_Star_Off.png" preload="false" />
<texture name="Favorite_Star_Press" file_name="navbar/Favorite_Star_Press.png" preload="false" />
@ -326,6 +329,8 @@ with the same filename but different name
<texture name="Locked_Icon" file_name="icons/Locked_Icon.png" preload="false" />
<texture name="Map_Placeholder_Icon" file_name="icons/map_placeholder.png" preload="true" />
<texture name="MarketplaceBtn_Off" file_name="widgets/MarketplaceBtn_Off.png" preload="true" scale.left="30" scale.top="19" scale.right="35" scale.bottom="4" />
<texture name="MarketplaceBtn_Selected" file_name="widgets/MarketplaceBtn_Selected.png" preload="true" scale.left="30" scale.top="19" scale.right="35" scale.bottom="4" />
@ -568,6 +573,7 @@ with the same filename but different name
<texture name="Snapshot_Email" file_name="snapshot_email.png" preload="false" />
<texture name="Snapshot_Inventory" file_name="toolbar_icons/inventory.png" preload="false" />
<texture name="Snapshot_Profile" file_name="toolbar_icons/profile.png" preload="false" />
<texture name="Snapshot_Facebook" file_name="toolbar_icons/facebook.png" preload="false" />
<texture name="startup_logo" file_name="windows/startup_logo.png" preload="true" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -1274,7 +1274,7 @@ Warten Sie kurz und versuchen Sie dann noch einmal, sich anzumelden.
https://marketplace.[MARKETPLACE_DOMAIN_NAME]/
</string>
<string name="MarketplaceURL_CreateStore">
http://community.secondlife.com/t5/English-Knowledge-Base/Selling-in-the-Marketplace/ta-p/700193#Section_.4
http://community.secondlife.com/t5/English-Knowledge-Base/Selling-in-the-Marketplace/ta-p/700193#Section_.3
</string>
<string name="MarketplaceURL_Dashboard">
https://marketplace.[MARKETPLACE_DOMAIN_NAME]/merchants/store/dashboard

View File

@ -1365,7 +1365,7 @@ Only large parcels can be listed in search.
<combo_box.item
label="Any Category"
name="item0"
value="any" />
value="none" />
<combo_box.item
label="Linden Location"
name="item1"

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<floater name="floater_fbc_web"
help_topic="fbc_web"
width="780"
height="775"
save_rect="true"
single_instance="true"
reuse_instance="false"
filename="floater_web_content.xml"/>

Some files were not shown because too many files have changed in this diff Show More